status.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5package lunatask
  6
  7import (
  8	"encoding/json"
  9	"errors"
 10	"fmt"
 11	"strings"
 12)
 13
 14// TaskStatus represents the workflow state of a task.
 15//
 16//nolint:recvcheck // MarshalJSON must use value receiver, UnmarshalJSON must use pointer
 17type TaskStatus string
 18
 19// Valid task status values.
 20const (
 21	// StatusLater is the default status for new tasks.
 22	StatusLater      TaskStatus = "later"
 23	StatusNext       TaskStatus = "next"
 24	StatusInProgress TaskStatus = "in-progress"
 25	StatusWaiting    TaskStatus = "waiting"
 26	StatusCompleted  TaskStatus = "completed"
 27)
 28
 29// Errors returned by TaskStatus operations.
 30var (
 31	// ErrInvalidTaskStatus is returned when parsing an unknown task status string.
 32	ErrInvalidTaskStatus = errors.New("invalid task status")
 33)
 34
 35// String returns the task status value as a string.
 36func (s TaskStatus) String() string {
 37	return string(s)
 38}
 39
 40// MarshalJSON implements [json.Marshaler].
 41// Translates "in-progress" to "started" for the API.
 42func (s TaskStatus) MarshalJSON() ([]byte, error) {
 43	val := string(s)
 44	if s == StatusInProgress {
 45		val = "started"
 46	}
 47
 48	data, err := json.Marshal(val)
 49	if err != nil {
 50		return nil, fmt.Errorf("marshaling task status: %w", err)
 51	}
 52
 53	return data, nil
 54}
 55
 56// UnmarshalJSON implements [json.Unmarshaler].
 57// Translates "started" from the API to "in-progress".
 58func (s *TaskStatus) UnmarshalJSON(data []byte) error {
 59	var val string
 60	if err := json.Unmarshal(data, &val); err != nil {
 61		return fmt.Errorf("task status must be a string: %w", err)
 62	}
 63
 64	if val == "started" {
 65		*s = StatusInProgress
 66
 67		return nil
 68	}
 69
 70	*s = TaskStatus(val)
 71
 72	return nil
 73}
 74
 75// AllTaskStatuses returns all valid task status values in workflow order.
 76func AllTaskStatuses() []TaskStatus {
 77	return []TaskStatus{
 78		StatusLater,
 79		StatusNext,
 80		StatusInProgress,
 81		StatusWaiting,
 82		StatusCompleted,
 83	}
 84}
 85
 86// ParseTaskStatus parses a string to a TaskStatus value (case-insensitive).
 87// Valid values: "later", "next", "in-progress", "waiting", "completed".
 88func ParseTaskStatus(str string) (TaskStatus, error) {
 89	switch strings.ToLower(str) {
 90	case "later":
 91		return StatusLater, nil
 92	case "next":
 93		return StatusNext, nil
 94	case "in-progress":
 95		return StatusInProgress, nil
 96	case "waiting":
 97		return StatusWaiting, nil
 98	case "completed":
 99		return StatusCompleted, nil
100	default:
101		return "", fmt.Errorf("%w: %q", ErrInvalidTaskStatus, str)
102	}
103}