A flat-YAML task tracker that is just files. No daemon, no database, no git hooks.
diarie.dev
issue-tracker
cli
nodejs
agent-friendly
1/**
2 * Status-filter flags.
3 *
4 * The group owns BOTH halves — the declaration and its meaning — so the two cannot
5 * drift apart. `validateFilterFlags` is pure: no filesystem, no printing, no process.
6 * It is therefore unit-testable without spawning anything, which is the entire point
7 * of lifting it out of `run()`.
8 */
9
10import { isStatus, VALID_STATUSES } from '../schema.js';
11import { InputError } from '../utils/errors.js';
12
13export const filterFlags = /** @satisfies {import('peowly').AnyFlags} */ ({
14 filter: {
15 description: `Show tasks in a given status (${[...VALID_STATUSES].join(', ')})`,
16 type: 'string',
17 },
18});
19
20/**
21 * @typedef FilterFlags
22 * @property {import('../schema.js').Status|undefined} filter
23 */
24
25/**
26 * @param {import('peowly').TypedFlags<typeof filterFlags>} flags
27 * @returns {FilterFlags}
28 * @throws {InputError} when the status is not one this store can hold
29 */
30export function validateFilterFlags ({ filter }) {
31 // Absent is not invalid — `--filter` is optional, and its absence selects the
32 // partition view rather than the list view. Only a PRESENT-and-wrong value is an error.
33 if (filter === undefined) return { filter: undefined };
34
35 // `isStatus`, not `VALID_STATUSES.has()`. A `Set<Status>` refuses a `string` argument
36 // outright, so this check used to cast through `any` — an `any`, at the exact
37 // validation boundary the Set existed to guard. The guard narrows instead.
38 if (!isStatus(filter)) {
39 throw new InputError(`--filter must be one of: ${[...VALID_STATUSES].join(', ')}`, undefined, 'EUSAGE');
40 }
41
42 return { filter };
43}