@@ -16,6 +16,8 @@ import (
var (
// ErrInvalidDeepLink is returned when parsing a malformed deep link.
ErrInvalidDeepLink = errors.New("invalid deep link")
+ // ErrInvalidReference is returned when input is neither a valid deep link nor UUID.
+ ErrInvalidReference = errors.New("invalid reference")
// ErrInvalidResource is returned when a resource type is unknown.
ErrInvalidResource = errors.New("invalid resource")
// ErrInvalidUUID is returned when the UUID portion is empty or malformed.
@@ -35,11 +37,16 @@ const (
ResourceNotebook Resource = "notebooks"
)
+// ResourceUnknown is returned when parsing a raw UUID without resource context.
+const ResourceUnknown Resource = ""
+
// Valid reports whether r is a known resource type.
func (r Resource) Valid() bool {
switch r {
case ResourceArea, ResourceGoal, ResourceTask, ResourceNote, ResourcePerson, ResourceNotebook:
return true
+ case ResourceUnknown:
+ return false
}
return false
@@ -63,13 +70,13 @@ func ValidateUUID(id string) error {
return nil
}
-// ParseDeepLink extracts resource type and UUID from a Lunatask deep link
+// ParseReference extracts resource type and UUID from a Lunatask deep link
// or plain UUID. Accepts "lunatask://tasks/uuid" or plain UUID strings.
-// When a plain UUID is provided, the resource type will be empty.
+// When a plain UUID is provided, the resource type will be ResourceUnknown.
// The UUID is validated to be a well-formed UUID string.
-func ParseDeepLink(input string) (Resource, string, error) {
+func ParseReference(input string) (Resource, string, error) {
if input == "" {
- return "", "", fmt.Errorf("%w: empty input", ErrInvalidDeepLink)
+ return "", "", fmt.Errorf("%w: empty input", ErrInvalidReference)
}
// Check for lunatask:// prefix
@@ -77,10 +84,10 @@ func ParseDeepLink(input string) (Resource, string, error) {
if !strings.HasPrefix(input, prefix) {
// Treat as plain UUID, validate format
if err := ValidateUUID(input); err != nil {
- return "", "", err
+ return "", "", fmt.Errorf("%w %q: expected UUID or lunatask:// deep link", ErrInvalidReference, input)
}
- return "", input, nil
+ return ResourceUnknown, input, nil
}
// Remove prefix and split
@@ -105,6 +112,13 @@ func ParseDeepLink(input string) (Resource, string, error) {
return resource, id, nil
}
+// ParseDeepLink extracts resource type and UUID from input.
+//
+// Deprecated: Use ParseReference instead.
+func ParseDeepLink(input string) (Resource, string, error) {
+ return ParseReference(input)
+}
+
// BuildDeepLink constructs a Lunatask deep link from resource type and ID.
// Returns "lunatask://resource/uuid". The ID is validated to be a well-formed UUID.
func BuildDeepLink(resource Resource, id string) (string, error) {
@@ -11,7 +11,7 @@ import (
lunatask "git.secluded.site/go-lunatask"
)
-func TestParseDeepLink(t *testing.T) {
+func TestParseReference(t *testing.T) {
t.Parallel()
validUUID := "12345678-1234-1234-1234-123456789012"
@@ -32,51 +32,70 @@ func TestParseDeepLink(t *testing.T) {
{"person_link", "lunatask://people/" + validUUID, lunatask.ResourcePerson, validUUID, nil},
{"notebook_link", "lunatask://notebooks/" + validUUID, lunatask.ResourceNotebook, validUUID, nil},
- // Plain UUIDs
- {"plain_uuid", validUUID2, "", validUUID2, nil},
- {"uuid_only", validUUID, "", validUUID, nil},
+ // Plain UUIDs return ResourceUnknown
+ {"plain_uuid", validUUID2, lunatask.ResourceUnknown, validUUID2, nil},
+ {"uuid_only", validUUID, lunatask.ResourceUnknown, validUUID, nil},
// Invalid inputs
- {"empty", "", "", "", lunatask.ErrInvalidDeepLink},
+ {"empty", "", "", "", lunatask.ErrInvalidReference},
{"invalid_resource", "lunatask://invalid/" + validUUID, "", "", lunatask.ErrInvalidResource},
{"missing_uuid", "lunatask://tasks/", "", "", lunatask.ErrInvalidDeepLink},
{"missing_resource", "lunatask:///" + validUUID, "", "", lunatask.ErrInvalidDeepLink},
{"malformed", "lunatask://tasks", "", "", lunatask.ErrInvalidDeepLink},
{"invalid_uuid_in_link", "lunatask://tasks/not-a-uuid", "", "", lunatask.ErrInvalidUUID},
- {"invalid_plain_uuid", "not-a-valid-uuid", "", "", lunatask.ErrInvalidUUID},
+ {"invalid_plain_uuid", "not-a-valid-uuid", "", "", lunatask.ErrInvalidReference},
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
- resource, uuid, err := lunatask.ParseDeepLink(testCase.input)
+ resource, uuid, err := lunatask.ParseReference(testCase.input)
if testCase.wantErr != nil {
if !errors.Is(err, testCase.wantErr) {
- t.Errorf("ParseDeepLink(%q) error = %v, want %v", testCase.input, err, testCase.wantErr)
+ t.Errorf("ParseReference(%q) error = %v, want %v", testCase.input, err, testCase.wantErr)
}
return
}
if err != nil {
- t.Errorf("ParseDeepLink(%q) unexpected error = %v", testCase.input, err)
+ t.Errorf("ParseReference(%q) unexpected error = %v", testCase.input, err)
return
}
if resource != testCase.wantResource {
- t.Errorf("ParseDeepLink(%q) resource = %q, want %q", testCase.input, resource, testCase.wantResource)
+ t.Errorf("ParseReference(%q) resource = %q, want %q", testCase.input, resource, testCase.wantResource)
}
if uuid != testCase.wantUUID {
- t.Errorf("ParseDeepLink(%q) uuid = %q, want %q", testCase.input, uuid, testCase.wantUUID)
+ t.Errorf("ParseReference(%q) uuid = %q, want %q", testCase.input, uuid, testCase.wantUUID)
}
})
}
}
+func TestParseDeepLink_Deprecated(t *testing.T) {
+ t.Parallel()
+
+ validUUID := "12345678-1234-1234-1234-123456789012"
+
+ resource, uuid, err := lunatask.ParseDeepLink("lunatask://tasks/" + validUUID)
+ if err != nil {
+ t.Errorf("ParseDeepLink() unexpected error = %v", err)
+ }
+
+ if resource != lunatask.ResourceTask {
+ t.Errorf("ParseDeepLink() resource = %q, want %q", resource, lunatask.ResourceTask)
+ }
+
+ if uuid != validUUID {
+ t.Errorf("ParseDeepLink() uuid = %q, want %q", uuid, validUUID)
+ }
+}
+
func TestBuildDeepLink(t *testing.T) {
t.Parallel()