// // Copyright 2022 DXOS.org // import sortBy from 'lodash.sortby'; const isPlainObject = (obj: any) => { return Object.prototype.toString.call(obj) === '[object Object]'; }; type Sorter = string[] | ((value: any) => any) type Options = { depth?: number, map?: { [key: string]: Sorter } } const createKeySorter = (key: string, { depth = -1, map }: Options) => { const order = map?.[key]; if (!order) { return (values: any[]) => { const d = key.split('.').length - 1; if (d < depth || depth === -1) { values.sort((key1: string, key2: string) => key1.localeCompare(key2)); } return values; } } if (Array.isArray(order)) { return (values: any[]) => { values.sort((key1: string, key2: string) => { const i1 = order.indexOf(key1); const i2 = order.indexOf(key2); if (i1 !== -1 && i2 !== -1) { return i1 < i2 ? -1 : i1 > i2 ? 1 : 0; } if (i1 !== -1) { return -1; } if (i2 !== -1) { return 1; } return key1.localeCompare(key2); }); return values; }; } }; const createValueSorter = (key: string, { map }: Options) => { const order = map?.[key]; if (typeof order === 'function') { return (values: any[]) => sortBy(values, order); } }; export const sort = (src: any, options: Options = {}, key = '.'): any => { let out: { [key: string]: any }; if (Array.isArray(src)) { let values = src.map((src, i) => sort(src, options, `${key}[${i}]`)); const sorter = createValueSorter(key, options); if (sorter) { values = sorter(values); } return values; } if (isPlainObject(src)) { out = {}; let keys = Object.keys(src); const sorter = createKeySorter(key, options); if (sorter) { keys = sorter(keys); } keys.forEach(subkey => { const value = src[subkey]; out[subkey] = sort(value, options, `${key === '.' ? '' : key}.${subkey}`); }); return out; } return src; }