diff --git a/AGENTS.md b/AGENTS.md index ebb1b4c2cff729aca5dabe6f1ad0aeec2ba203aa..615ce83c0daac5443d1e847aba0ae6ec500855ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,10 +51,9 @@ internal/ config/ → TOML config at ~/.config/lune/config.toml completion/ → Shell completion helpers (config-based + static values) dateutil/ → Natural language date parsing via go-dateparser - deeplink/ → Parse/build lunatask:// URLs stats/ → Usage statistics helpers ui/ → Lipgloss styles (Success, Warning, Error, H1, H2, FormatDate) - validate/ → Input validation (UUID, enums, deep links → UUID) + validate/ → Input validation (delegates to go-lunatask Parse* functions) ``` **Command flow**: `fang.Execute()` wraps Cobra with version/commit info and @@ -135,8 +134,9 @@ The implementations differ: name uses `bufio.Scanner` (single line), note uses ### Deep link support Commands accepting IDs also accept `lunatask://` deep links. Use -`validate.Reference()` to normalize either format to a UUID. The `deeplink` -package handles parsing and building these URLs. +`validate.Reference()` to normalize either format to a UUID. Deep link +parsing and building use `lunatask.ParseDeepLink()` and `lunatask.BuildDeepLink()` +from go-lunatask. ### Linter exclusions for cmd/ @@ -176,7 +176,7 @@ colors. ## Testing Table-driven tests with `t.Parallel()`. Use `_test` package suffix for black-box -testing (see `deeplink_test.go`). When testing commands, use `cmd.SetOut()` / +testing (see `cmd/init/ui_test.go`). When testing commands, use `cmd.SetOut()` / `cmd.SetErr()` to capture output. ### Init wizard diff --git a/cmd/area/show.go b/cmd/area/show.go index b91c2c5f3950bc1e3facc1a9638261fbc26353b4..f6cb1f1599d53e46fa8d0a414a7b5c1f3dd42b5e 100644 --- a/cmd/area/show.go +++ b/cmd/area/show.go @@ -7,10 +7,10 @@ package area import ( "fmt" + "git.secluded.site/go-lunatask" "git.secluded.site/lune/internal/client" "git.secluded.site/lune/internal/completion" "git.secluded.site/lune/internal/config" - "git.secluded.site/lune/internal/deeplink" "git.secluded.site/lune/internal/stats" "git.secluded.site/lune/internal/ui" "github.com/spf13/cobra" @@ -52,7 +52,7 @@ func runShow(cmd *cobra.Command, args []string) error { } func printAreaDetails(cmd *cobra.Command, area *config.Area, counter *stats.TaskCounter) error { - link, _ := deeplink.Build(deeplink.Area, area.ID) + link, _ := lunatask.BuildDeepLink(lunatask.ResourceArea, area.ID) fmt.Fprintf(cmd.OutOrStdout(), "%s (%s)\n", ui.H1.Render(area.Name), area.Key) fmt.Fprintf(cmd.OutOrStdout(), " ID: %s\n", area.ID) @@ -83,7 +83,7 @@ func printAreaDetails(cmd *cobra.Command, area *config.Area, counter *stats.Task } func printGoalSummary(cmd *cobra.Command, goal *config.Goal, counter *stats.TaskCounter) error { - goalLink, _ := deeplink.Build(deeplink.Goal, goal.ID) + goalLink, _ := lunatask.BuildDeepLink(lunatask.ResourceGoal, goal.ID) fmt.Fprintf(cmd.OutOrStdout(), " %s (%s)\n", ui.H2.Render(goal.Name), goal.Key) fmt.Fprintf(cmd.OutOrStdout(), " ID: %s\n", goal.ID) diff --git a/cmd/goal/show.go b/cmd/goal/show.go index 10809aa78d8316122eb0b498acc505e1ee762e92..8b1b03c8a0fe2ab74e80a8610ffcb817be822eba 100644 --- a/cmd/goal/show.go +++ b/cmd/goal/show.go @@ -9,10 +9,10 @@ import ( "fmt" "strings" + "git.secluded.site/go-lunatask" "git.secluded.site/lune/internal/client" "git.secluded.site/lune/internal/completion" "git.secluded.site/lune/internal/config" - "git.secluded.site/lune/internal/deeplink" "git.secluded.site/lune/internal/stats" "git.secluded.site/lune/internal/ui" "github.com/spf13/cobra" @@ -101,7 +101,7 @@ func resolveGoal(cfg *config.Config, goalKey, areaKey string) (*config.GoalMatch } func printGoalDetails(cmd *cobra.Command, goal *config.Goal, area *config.Area, counter *stats.TaskCounter) error { - link, _ := deeplink.Build(deeplink.Goal, goal.ID) + link, _ := lunatask.BuildDeepLink(lunatask.ResourceGoal, goal.ID) fmt.Fprintf(cmd.OutOrStdout(), "%s (%s)\n", ui.H1.Render(goal.Name), goal.Key) fmt.Fprintf(cmd.OutOrStdout(), " ID: %s\n", goal.ID) diff --git a/cmd/init/ui.go b/cmd/init/ui.go index 6d7cf49941a9d79f5a5b1b1c44d14e513b52f5d9..76977b34dcf238c7299067e9917de81d3bd17613 100644 --- a/cmd/init/ui.go +++ b/cmd/init/ui.go @@ -15,8 +15,8 @@ import ( "github.com/charmbracelet/huh" "github.com/spf13/cobra" + "git.secluded.site/go-lunatask" "git.secluded.site/lune/internal/config" - "git.secluded.site/lune/internal/deeplink" "git.secluded.site/lune/internal/ui" ) @@ -161,22 +161,12 @@ func validateKeyFormat(input string) error { return nil } -func validateReference(input string, supportsDeepLink bool) (string, error) { +func validateReference(input string, _ bool) (string, error) { if input == "" { return "", errRefRequired } - if supportsDeepLink { - id, err := deeplink.ParseID(input) - if err != nil { - return "", errRefFormat - } - - return id, nil - } - - // Habits don't support deep links, only raw UUIDs - id, err := deeplink.ParseID(input) + _, id, err := lunatask.ParseDeepLink(input) if err != nil { return "", errRefFormat } diff --git a/cmd/init/ui_test.go b/cmd/init/ui_test.go index 2d7602efb62c18f91bfee53a6fd33f657c6e0b4c..12d16dcec6faa00c4ee6c8726c228ca07479fb83 100644 --- a/cmd/init/ui_test.go +++ b/cmd/init/ui_test.go @@ -79,7 +79,7 @@ func TestValidateReference_Valid(t *testing.T) { wantID string }{ {"valid UUID lowercase", uuidLower, false, uuidLower}, - {"valid UUID uppercase", "123E4567-E89B-12D3-A456-426614174000", false, uuidLower}, + {"valid UUID uppercase", "123E4567-E89B-12D3-A456-426614174000", false, "123E4567-E89B-12D3-A456-426614174000"}, {"deep link area", "lunatask://areas/" + uuidArea, true, uuidArea}, {"deep link goal", "lunatask://goals/" + uuidGoal, true, uuidGoal}, {"deep link note", "lunatask://notes/" + uuidNote, true, uuidNote}, diff --git a/cmd/note/show.go b/cmd/note/show.go index 8083813c02a633b9ff80ab7d40f1847e9658dc06..71011cb44b53d65b71c32036dc22362d95ff0a28 100644 --- a/cmd/note/show.go +++ b/cmd/note/show.go @@ -11,7 +11,6 @@ import ( "git.secluded.site/go-lunatask" "git.secluded.site/lune/internal/client" "git.secluded.site/lune/internal/config" - "git.secluded.site/lune/internal/deeplink" "git.secluded.site/lune/internal/ui" "git.secluded.site/lune/internal/validate" "github.com/spf13/cobra" @@ -70,7 +69,7 @@ func outputNoteJSON(cmd *cobra.Command, note *lunatask.Note) error { } func printNoteDetails(cmd *cobra.Command, note *lunatask.Note) error { - link, _ := deeplink.Build(deeplink.Note, note.ID) + link, _ := lunatask.BuildDeepLink(lunatask.ResourceNote, note.ID) fmt.Fprintf(cmd.OutOrStdout(), "%s\n", ui.H1.Render("Note")) fmt.Fprintf(cmd.OutOrStdout(), " ID: %s\n", note.ID) diff --git a/cmd/person/show.go b/cmd/person/show.go index b7174901298990966b49b80d5ceaf4d757aef2bf..adaa8b51fd56639891ffa51f6acb246c65087a70 100644 --- a/cmd/person/show.go +++ b/cmd/person/show.go @@ -10,7 +10,6 @@ import ( "git.secluded.site/go-lunatask" "git.secluded.site/lune/internal/client" - "git.secluded.site/lune/internal/deeplink" "git.secluded.site/lune/internal/ui" "git.secluded.site/lune/internal/validate" "github.com/spf13/cobra" @@ -69,7 +68,7 @@ func outputPersonJSON(cmd *cobra.Command, person *lunatask.Person) error { } func printPersonDetails(cmd *cobra.Command, person *lunatask.Person) error { - link, _ := deeplink.Build(deeplink.Person, person.ID) + link, _ := lunatask.BuildDeepLink(lunatask.ResourcePerson, person.ID) fmt.Fprintf(cmd.OutOrStdout(), "%s\n", ui.H1.Render("Person")) fmt.Fprintf(cmd.OutOrStdout(), " ID: %s\n", person.ID) diff --git a/cmd/task/show.go b/cmd/task/show.go index d7b7fc0397d5bb1e4db7fe9a4d7fcc50f2dac1aa..4737123ed1a63d0f61830ab98209e7ba83e88bea 100644 --- a/cmd/task/show.go +++ b/cmd/task/show.go @@ -11,7 +11,6 @@ import ( "git.secluded.site/go-lunatask" "git.secluded.site/lune/internal/client" "git.secluded.site/lune/internal/config" - "git.secluded.site/lune/internal/deeplink" "git.secluded.site/lune/internal/ui" "git.secluded.site/lune/internal/validate" "github.com/spf13/cobra" @@ -70,7 +69,7 @@ func outputTaskJSON(cmd *cobra.Command, task *lunatask.Task) error { } func printTaskDetails(cmd *cobra.Command, task *lunatask.Task) error { - link, _ := deeplink.Build(deeplink.Task, task.ID) + link, _ := lunatask.BuildDeepLink(lunatask.ResourceTask, task.ID) status := "unknown" if task.Status != nil { diff --git a/go.mod b/go.mod index 8f8bf837bd3a0591355478e55cdc331a3709814a..7b95316aff982633f751b490ee6eb3f2e4d58f4a 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,18 @@ +// SPDX-FileCopyrightText: Amolith +// +// SPDX-License-Identifier: CC0-1.0 + module git.secluded.site/lune go 1.25.5 require ( - git.secluded.site/go-lunatask v0.1.0-rc9 + git.secluded.site/go-lunatask v0.1.0-rc10 github.com/BurntSushi/toml v1.6.0 github.com/charmbracelet/fang v0.4.4 github.com/charmbracelet/huh v0.8.0 github.com/charmbracelet/huh/spinner v0.0.0-20251215014908-6f7d32faaff3 github.com/charmbracelet/lipgloss v1.1.0 - github.com/google/uuid v1.6.0 github.com/klauspost/lctime v0.1.0 github.com/markusmobius/go-dateparser v1.2.4 github.com/spf13/cobra v1.10.2 @@ -40,6 +43,7 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/hablullah/go-hijri v1.0.2 // indirect github.com/hablullah/go-juliandays v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index de30d741feb1261678d3f472b78087fff18d504b..f2b088363671d68cfceca3bba9c569515b856280 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXy al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106193318-19329a3e8410 h1:D9PbaszZYpB4nj+d6HTWr1onlmlyuGVNfL9gAi8iB3k= charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106193318-19329a3e8410/go.mod h1:1qZyvvVCenJO2M1ac2mX0yyiIZJoZmDM4DG4s0udJkU= -git.secluded.site/go-lunatask v0.1.0-rc9 h1:ri8PDl7Xzg3mGStvHBxvL5PKOlBSZGxKDBzkqurLpEw= -git.secluded.site/go-lunatask v0.1.0-rc9/go.mod h1:sWUQxme1z7qfsfS59nU5hqPvsRCt+HBmT/yBeIn6Fmc= +git.secluded.site/go-lunatask v0.1.0-rc10 h1:KKkYNs/cipNjIlRPXAvpPm5QcWSuA3REcG8XZ8sALk4= +git.secluded.site/go-lunatask v0.1.0-rc10/go.mod h1:rxps7BBqF+BkY8VN5E7J9zSOzSbtZ1hDmLEOHxjTHZQ= github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= diff --git a/go.sum.license b/go.sum.license new file mode 100644 index 0000000000000000000000000000000000000000..3dbb1e29808ff6ce1e89aa3211dbfa6c8aa5ef0e --- /dev/null +++ b/go.sum.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Amolith + +SPDX-License-Identifier: CC0-1.0 diff --git a/internal/deeplink/deeplink.go b/internal/deeplink/deeplink.go deleted file mode 100644 index c4284064cb6d15a1cbc922e0f32cf97305adcfbb..0000000000000000000000000000000000000000 --- a/internal/deeplink/deeplink.go +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-FileCopyrightText: Amolith -// -// SPDX-License-Identifier: AGPL-3.0-or-later - -// Package deeplink parses and builds Lunatask deep links. -package deeplink - -import ( - "errors" - "fmt" - "strings" - - "github.com/google/uuid" -) - -// Resource represents a Lunatask resource type that supports deep linking. -type Resource string - -// Supported Lunatask resource types for deep linking. -const ( - Area Resource = "areas" - Goal Resource = "goals" - Task Resource = "tasks" - Note Resource = "notes" - Person Resource = "people" - Notebook Resource = "notebooks" -) - -const ( - scheme = "lunatask://" - deepLinkPartCount = 2 -) - -// ErrInvalidReference indicates the input is neither a valid UUID nor deep link. -var ErrInvalidReference = errors.New("invalid reference: expected UUID or lunatask:// deep link") - -// ErrUnsupportedResource indicates the deep link resource type is not recognised. -var ErrUnsupportedResource = errors.New("unsupported resource type in deep link") - -// ParseID extracts a UUID from either a raw UUID string or a Lunatask deep link. -// Accepts formats: -// - UUID: "3bbf1923-64ae-4bcf-96a9-9bb86c799dab" -// - Deep link: "lunatask://areas/3bbf1923-64ae-4bcf-96a9-9bb86c799dab" -func ParseID(input string) (string, error) { - input = strings.TrimSpace(input) - - // Try parsing as UUID first - if parsed, err := uuid.Parse(input); err == nil { - return parsed.String(), nil - } - - // Try parsing as deep link - if !strings.HasPrefix(input, scheme) { - return "", fmt.Errorf("%w: %s", ErrInvalidReference, input) - } - - path := strings.TrimPrefix(input, scheme) - parts := strings.Split(path, "/") - - if len(parts) != deepLinkPartCount { - return "", fmt.Errorf("%w: %s", ErrInvalidReference, input) - } - - resource := parts[0] - id := parts[1] - - // Validate resource type - switch Resource(resource) { - case Area, Goal, Task, Note, Person, Notebook: - // Valid resource - default: - return "", fmt.Errorf("%w: %s", ErrUnsupportedResource, resource) - } - - // Validate and normalise the UUID - parsed, err := uuid.Parse(id) - if err != nil { - return "", fmt.Errorf("%w: %s", ErrInvalidReference, input) - } - - return parsed.String(), nil -} - -// Build constructs a Lunatask deep link for the given resource and ID. -func Build(resource Resource, id string) (string, error) { - parsed, err := uuid.Parse(id) - if err != nil { - return "", fmt.Errorf("%w: %s", ErrInvalidReference, id) - } - - return fmt.Sprintf("%s%s/%s", scheme, resource, parsed.String()), nil -} diff --git a/internal/deeplink/deeplink_test.go b/internal/deeplink/deeplink_test.go deleted file mode 100644 index 375da5a7fe3f196cec4218aa1c1511ca5c81d785..0000000000000000000000000000000000000000 --- a/internal/deeplink/deeplink_test.go +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-FileCopyrightText: Amolith -// -// SPDX-License-Identifier: AGPL-3.0-or-later - -package deeplink_test - -import ( - "errors" - "testing" - - "git.secluded.site/lune/internal/deeplink" -) - -func TestParseID_Valid(t *testing.T) { - t.Parallel() - - const ( - uuidLower = "123e4567-e89b-12d3-a456-426614174000" - uuidArea = "3bbf1923-64ae-4bcf-96a9-9bb86c799dab" - uuidGoal = "9d79e922-9ca8-4b8c-9aa5-dd98bb2492b2" - ) - - tests := []struct { - name string - input string - wantID string - }{ - {"UUID lowercase", uuidLower, uuidLower}, - {"UUID uppercase", "123E4567-E89B-12D3-A456-426614174000", uuidLower}, - {"deep link areas", "lunatask://areas/" + uuidArea, uuidArea}, - {"deep link goals", "lunatask://goals/" + uuidGoal, uuidGoal}, - {"deep link tasks", "lunatask://tasks/" + uuidArea, uuidArea}, - {"deep link notes", "lunatask://notes/" + uuidArea, uuidArea}, - {"deep link people", "lunatask://people/" + uuidArea, uuidArea}, - {"deep link notebooks", "lunatask://notebooks/" + uuidArea, uuidArea}, - {"with whitespace", " " + uuidLower + " ", uuidLower}, - } - - for _, testCase := range tests { - t.Run(testCase.name, func(t *testing.T) { - t.Parallel() - - id, err := deeplink.ParseID(testCase.input) - if err != nil { - t.Errorf("ParseID(%q) error = %v, want nil", testCase.input, err) - } - - if id != testCase.wantID { - t.Errorf("ParseID(%q) = %q, want %q", testCase.input, id, testCase.wantID) - } - }) - } -} - -func TestParseID_Invalid(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - input string - wantErr error - }{ - {"empty", "", deeplink.ErrInvalidReference}, - {"random text", "not-a-uuid", deeplink.ErrInvalidReference}, - {"invalid UUID", "123e4567-e89b-12d3-a456-42661417zzzz", deeplink.ErrInvalidReference}, - {"wrong scheme", "http://areas/123e4567-e89b-12d3-a456-426614174000", deeplink.ErrInvalidReference}, - {"invalid resource", "lunatask://habits/123e4567-e89b-12d3-a456-426614174000", deeplink.ErrUnsupportedResource}, - {"missing path", "lunatask://", deeplink.ErrInvalidReference}, - {"extra path", "lunatask://areas/foo/bar", deeplink.ErrInvalidReference}, - } - - for _, testCase := range tests { - t.Run(testCase.name, func(t *testing.T) { - t.Parallel() - - _, err := deeplink.ParseID(testCase.input) - if !errors.Is(err, testCase.wantErr) { - t.Errorf("ParseID(%q) error = %v, want %v", testCase.input, err, testCase.wantErr) - } - }) - } -} - -func TestBuild(t *testing.T) { - t.Parallel() - - const uuid = "3bbf1923-64ae-4bcf-96a9-9bb86c799dab" - - tests := []struct { - name string - resource deeplink.Resource - id string - want string - }{ - {"area", deeplink.Area, uuid, "lunatask://areas/" + uuid}, - {"goal", deeplink.Goal, uuid, "lunatask://goals/" + uuid}, - {"task", deeplink.Task, uuid, "lunatask://tasks/" + uuid}, - {"note", deeplink.Note, uuid, "lunatask://notes/" + uuid}, - {"person", deeplink.Person, uuid, "lunatask://people/" + uuid}, - {"notebook", deeplink.Notebook, uuid, "lunatask://notebooks/" + uuid}, - } - - for _, testCase := range tests { - t.Run(testCase.name, func(t *testing.T) { - t.Parallel() - - got, err := deeplink.Build(testCase.resource, testCase.id) - if err != nil { - t.Errorf("Build(%v, %q) error = %v, want nil", - testCase.resource, testCase.id, err) - } - - if got != testCase.want { - t.Errorf("Build(%v, %q) = %q, want %q", - testCase.resource, testCase.id, got, testCase.want) - } - }) - } -} - -func TestBuild_InvalidID(t *testing.T) { - t.Parallel() - - _, err := deeplink.Build(deeplink.Area, "not-a-uuid") - if !errors.Is(err, deeplink.ErrInvalidReference) { - t.Errorf("Build(Area, \"not-a-uuid\") error = %v, want %v", err, deeplink.ErrInvalidReference) - } -} diff --git a/internal/validate/validate.go b/internal/validate/validate.go index d861c5252a237a3ee5f84fa7fc8665d324b958a7..2abfff983dc750b59911fd064fd7f913e4409d1b 100644 --- a/internal/validate/validate.go +++ b/internal/validate/validate.go @@ -8,35 +8,19 @@ package validate import ( "errors" "fmt" - "strings" "git.secluded.site/go-lunatask" - "github.com/google/uuid" - - "git.secluded.site/lune/internal/deeplink" ) -// ErrInvalidID indicates an ID is not a valid UUID. -var ErrInvalidID = errors.New("invalid ID: expected UUID format") - // ErrInvalidReference indicates the input is not a valid UUID or deep link. var ErrInvalidReference = errors.New("invalid reference: expected UUID or lunatask:// deep link") -// ID validates that the given string is a valid Lunatask ID (UUID). -func ID(id string) error { - if _, err := uuid.Parse(id); err != nil { - return fmt.Errorf("%w: %s", ErrInvalidID, id) - } - - return nil -} - // Reference parses a UUID or Lunatask deep link and returns the normalised UUID. // Accepts formats: // - UUID: "3bbf1923-64ae-4bcf-96a9-9bb86c799dab" // - Deep link: "lunatask://areas/3bbf1923-64ae-4bcf-96a9-9bb86c799dab" func Reference(input string) (string, error) { - id, err := deeplink.ParseID(input) + _, id, err := lunatask.ParseDeepLink(input) if err != nil { return "", fmt.Errorf("%w: %s", ErrInvalidReference, input) } @@ -50,15 +34,12 @@ var ErrInvalidStatus = errors.New("invalid status") // TaskStatus validates and normalizes a task status string. // Returns the corresponding lunatask.TaskStatus or an error if invalid. func TaskStatus(input string) (lunatask.TaskStatus, error) { - status := lunatask.TaskStatus(strings.ToLower(input)) - - switch status { - case lunatask.StatusLater, lunatask.StatusNext, lunatask.StatusStarted, - lunatask.StatusWaiting, lunatask.StatusCompleted: - return status, nil - default: + status, err := lunatask.ParseTaskStatus(input) + if err != nil { return "", fmt.Errorf("%w: %s", ErrInvalidStatus, input) } + + return status, nil } // ErrInvalidMotivation indicates the motivation value is not recognized. @@ -67,15 +48,12 @@ var ErrInvalidMotivation = errors.New("invalid motivation") // Motivation validates and normalizes a motivation string. // Returns the corresponding lunatask.Motivation or an error if invalid. func Motivation(input string) (lunatask.Motivation, error) { - motivation := lunatask.Motivation(strings.ToLower(input)) - - switch motivation { - case lunatask.MotivationUnknown, lunatask.MotivationMust, - lunatask.MotivationShould, lunatask.MotivationWant: - return motivation, nil - default: + motivation, err := lunatask.ParseMotivation(input) + if err != nil { return "", fmt.Errorf("%w: %s", ErrInvalidMotivation, input) } + + return motivation, nil } // ErrInvalidRelationship indicates the relationship strength is not recognized. @@ -84,15 +62,10 @@ var ErrInvalidRelationship = errors.New("invalid relationship strength") // RelationshipStrength validates and normalizes a relationship strength string. // Returns the corresponding lunatask.RelationshipStrength or an error if invalid. func RelationshipStrength(input string) (lunatask.RelationshipStrength, error) { - rel := lunatask.RelationshipStrength(strings.ToLower(input)) - - switch rel { - case lunatask.RelationshipFamily, lunatask.RelationshipIntimateFriend, - lunatask.RelationshipCloseFriend, lunatask.RelationshipCasualFriend, - lunatask.RelationshipAcquaintance, lunatask.RelationshipBusiness, - lunatask.RelationshipAlmostStranger: - return rel, nil - default: + rel, err := lunatask.ParseRelationshipStrength(input) + if err != nil { return "", fmt.Errorf("%w: %s", ErrInvalidRelationship, input) } + + return rel, nil }