johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
// A filter of pulls and issues, in the words knotless-serve reads
// (crates/knotless/src/query.rs): `label:kind/bug -label:area/web
// author:alice.test crash`. The pages change it a term at a time.
/** `q` split on spaces, except within double quotes, each term as written. */
export function terms(q: string): string[] {
return q.match(/(?:[^\s"]+|"[^"]*"?)+/g) ?? [];
}
/** A term's key and its value, its quotes taken off. */
function parts(term: string): [string, string] {
const at = term.indexOf(':');
return at < 0 ? ['', term] : [term.slice(0, at), term.slice(at + 1).replaceAll('"', '')];
}
const stateTerm = /^(?:state|is):(?:open|closed|merged)$/;
/** Whether `q` asks for the closed (or merged) ones, else the open, `state` if it says neither. */
export function closed(q: string, state?: string | null): boolean {
const said = terms(q).findLast((t) => stateTerm.test(t));
return said ? !said.endsWith(':open') : state === 'closed';
}
/** `q` asking for the open ones or the closed. */
export function withState(q: string, state: 'open' | 'closed'): string {
return [`state:${state}`, ...terms(q).filter((t) => !stateTerm.test(t))].join(' ');
}
/** Whether `q` has a `key:` term of `value`. */
export function has(q: string, key: string, value: string): boolean {
return terms(q).some((t) => {
const [k, v] = parts(t);
return k === key && v === value;
});
}
/** `q` with a `key:` term of `value`, as it is if it has one. */
export function withTerm(q: string, key: string, value: string): string {
if (has(q, key, value)) return q;
return [...terms(q), `${key}:${/\s/.test(value) ? `"${value}"` : value}`].join(' ');
}
/** `q` with its `key:` term of `value` taken off, or put on if it has none. */
export function toggled(q: string, key: string, value: string): string {
if (!has(q, key, value)) return withTerm(q, key, value);
return terms(q)
.filter((t) => {
const [k, v] = parts(t);
return k !== key || v !== value;
})
.join(' ');
}
/** Whether `q` filters by more than state. */
export function filtered(q: string): boolean {
return terms(q).some((t) => !stateTerm.test(t));
}
/** The address of the list `q` filters, from the list's own. */
export function filterHref(q: string, cursor?: string): string {
const params = new URLSearchParams();
if (q.trim()) params.set('q', q.trim());
if (cursor) params.set('cursor', cursor);
return `?${params}`;
}