UNPKG

todo-txt-cli

Version:

A CLI for todo.txt files - http://todotxt.org/

85 lines (74 loc) 2.17 kB
/** * @typedef {(a: Record<string, any>, b: Record<string, any>) => number} ObjectSorter */ /** * @typedef {(property: string) => ObjectSorter} Sorter */ const noneSorter = (_a, _b) => 0 const undef = (a, b) => (!a && !b ? 0 : !a ? 1 : !b ? -1 : undefined) /** * @param {string} p * @returns {ObjectSorter} */ export const numSorter = (p) => (a, b) => undef(a[p], b[p]) ?? a[p] - b[p] /** * keeps sorting order if both object use property `p` * @param {string} p * @returns {ObjectSorter} */ export const boolSorter = (p) => (a, b) => a[p] && b[p] ? 1 : a[p] ? 1 : b[p] ? -1 : 0 /** * @param {string} p * @returns {ObjectSorter} */ export const stringSorter = (p) => (a, b) => undef(a[p], b[p]) ?? a[p].localeCompare(b[p]) export const sortSet = (set) => set ? [...set].sort((a, b) => a.localeCompare(b)) : [] /** * set values are sorted, concatenated and compared * @param {string} p * @returns {ObjectSorter} */ const setSorter = (p) => (a, b) => { const aset = sortSet(a[p]).join(',') const bset = sortSet(b[p]).join(',') return undef(aset, bset) ?? aset.localeCompare(bset) } export const sorting = { due: ['isCompleted', 'dueAt', 'priority', 'projects', 'contexts', 'task'], pri: ['isCompleted', 'priority', 'dueAt', 'task'], prj: ['isCompleted', 'projects', 'priority', 'dueAt', 'contexts', 'task'], con: ['isCompleted', 'contexts', 'priority', 'dueAt', 'projects', 'task'], task: ['isCompleted', 'task'] } /** @type {Record<string, ObjectSorter>} */ const _sorters = { id: stringSorter('id'), contexts: setSorter('contexts'), createdAt: numSorter('createdAt'), dueAt: numSorter('dueAt'), isCompleted: boolSorter('isCompleted'), priority: stringSorter('priority'), projects: setSorter('projects'), task: stringSorter('task') } /** * @param {string[]} sortOrder * @param {Record<string,ObjectSorter>} [sorters] * @returns */ export const sorter = (sortOrder, sorters = _sorters) => (a, b) => { let result = 0 for (const prop of sortOrder) { let fn = sorters[prop] || noneSorter result = fn(a, b) if (result !== 0) { break } } return result }