Packages

fnord

0.9.31

AI code archaeology

Current section

Files

Jump to
fnord lib services task list.ex
Raw

lib/services/task/list.ex

defmodule Services.Task.List do
@moduledoc """
Represents a task list with an identifier, optional description, and a list of tasks.
Provides core operations for creating and manipulating task lists.
"""
defstruct id: nil, description: nil, tasks: [], status: "planning"
# "planning" | "in-progress" | "done"
@type status :: String.t()
@type t :: %__MODULE__{
id: binary,
description: binary | nil,
tasks: [map()],
status: status
}
@doc """
Creates a new TaskList with the given `id` and optional `description`.
"""
@spec new(binary, binary | nil) :: t
def new(id, description \\ nil) when is_binary(id) do
%__MODULE__{id: id, description: description, tasks: [], status: "planning"}
end
@doc """
Adds a task to the end of the task list.
"""
@spec add(t, map()) :: t
def add(%__MODULE__{tasks: tasks} = list, task) when is_map(task) do
%__MODULE__{list | tasks: tasks ++ [task]}
end
@doc """
Pushes a task to the front of the task list.
"""
@spec push(t, map()) :: t
def push(%__MODULE__{tasks: tasks} = list, task) when is_map(task) do
%__MODULE__{list | tasks: [task | tasks]}
end
@doc """
Resolves tasks with the given `task_id` by updating their `outcome` and `result`.
Only tasks in todo state are updated.
"""
@spec resolve(t, binary, :done | :failed, any()) ::
{:ok, t} | {:error, :already_resolved | :not_found}
def resolve(%__MODULE__{tasks: tasks} = list, task_id, outcome, result)
when is_binary(task_id) and outcome in [:done, :failed] do
case Enum.find(tasks, fn %{id: id} -> id == task_id end) do
nil ->
{:error, :not_found}
%{outcome: :todo} ->
updated_tasks =
Enum.map(tasks, fn
%{id: ^task_id, outcome: :todo} = task ->
%{task | outcome: outcome, result: result}
other ->
other
end)
{:ok, %__MODULE__{list | tasks: updated_tasks}}
%{outcome: _terminal} ->
{:error, :already_resolved}
end
end
@doc """
Converts the task list to a string, including the header and each task.
If `detail?` is true, includes task results for done/failed tasks.
"""
@spec to_string(t, boolean) :: binary
def to_string(%__MODULE__{id: id, description: desc, tasks: tasks}, detail? \\ false) do
# Always include colon for consistency with Services.Task.as_string/2
header =
case desc do
nil -> "Task List #{id}:"
"" -> "Task List #{id}:"
_ -> "Task List #{id}: #{desc}"
end
body =
tasks
|> Enum.map(&format_task(&1, detail?))
Enum.join([header | body], "\n")
end
defp format_task(%{id: id, outcome: :todo}, _detail?),
do: "[ ] #{id}"
defp format_task(%{id: id, outcome: :done, result: result}, true),
do: "[✓] #{id}: #{result}"
defp format_task(%{id: id, outcome: :done}, false),
do: "[✓] #{id}"
defp format_task(%{id: id, outcome: :failed, result: result}, true),
do: "[✗] #{id}: #{result}"
defp format_task(%{id: id, outcome: :failed}, false),
do: "[✗] #{id}"
end