Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::todo_item::{validate_draft, Todo, TodoDraft}; ← from todo.item ^1.0.0 · built alongside by fune
use super::todo_item_validate_draft::{todo_draft_from_value, trim_space};
use super::todo_item_validate_todo::{is_utc_timestamp, todos_from_value, todos_to_value};
use super::todo_normalise_tags::normalise_tags; ← from todo.normalise-tags ^1.0.0 · built alongside by fune
/// Refuse a clock reading that would not compare as a string with the stored ones.
pub fn require_utc_now(now: &str) {
if !is_utc_timestamp(now) {
panic!("now must be a UTC timestamp like 2026-09-28T09:30:00Z");
}
}
/// The draft as it will be stored: title and notes trimmed (ASCII only),
/// blank notes as None, tags in normal form. Then checked with validate_draft;
/// the first field in field order that fails is the error.
pub fn checked_draft(draft: &TodoDraft) -> TodoDraft {
let notes = draft.notes.as_deref().map(trim_space).unwrap_or("");
let clean = TodoDraft {
title: trim_space(&draft.title).to_string(),
notes: if notes.is_empty() { None } else { Some(notes.to_string()) },
priority: draft.priority.clone(),
due: draft.due.clone(),
tags: normalise_tags(&draft.tags),
recurrence: draft.recurrence.clone(),
};
let verdict = validate_draft(&clean);
if let Some((field, message)) = verdict.errors.first() {
panic!("invalid todo: {}: {}", field, message);
}
clean
}
/// Add a todo from the add form: open, created now, last in manual order,
/// appended. Caller mistakes (id, clock) are reported before form mistakes.
///
/// # Panics
/// On a blank or duplicate id, a `now` that is not a UTC timestamp, or an
/// invalid draft.
pub fn add_todo(todos: &[Todo], draft: &TodoDraft, id: &str, now: &str) -> Vec<Todo> {
if trim_space(id).is_empty() {
panic!("a todo needs an id");
}
if todos.iter().any(|t| t.id == id) {
panic!("a todo with id \"{}\" already exists", id);
}
require_utc_now(now);
let clean = checked_draft(draft);
let order = todos.iter().map(|t| t.order + 1).fold(0, i64::max);
let mut out = todos.to_vec();
out.push(Todo {
id: id.to_string(),
title: clean.title,
notes: clean.notes,
done: false,
priority: clean.priority,
due: clean.due,
tags: clean.tags,
recurrence: clean.recurrence,
created_at: now.to_string(),
completed_at: None,
order,
});
out
}
pub fn fune_vector(args: &[Value]) -> Value {
let todos = todos_from_value(&args[0]);
todos_to_value(&add_todo(&todos, &todo_draft_from_value(&args[1]), args[2].as_str(), args[3].as_str()))
}