UNPKG

@nullvoxpopuli/ember-composable-helpers

Version:
175 lines (167 loc) 4.5 kB
import { get } from '@ember/object'; import { isEmpty } from '@ember/utils'; import { helper } from '@ember/component/helper'; import '@ember/array'; import asArray from '../utils/as-array.js'; const collator = new Intl.Collator(undefined, { sensitivity: 'base' }); function normalizeToBoolean(val) { if (typeof val === 'boolean') { return val; } if (typeof val === 'number') { if (val > 0) { return false; } else if (val < 0) { return true; } } return val; } function safeValueForKey(ctx, key) { if (ctx === null || ctx === undefined) { return ctx; } return get(ctx, key); } function sortDesc(key, a, b) { if (isEmpty(key)) { return 0; } // eslint-disable-next-line @typescript-eslint/no-explicit-any const aValue = safeValueForKey(a, key); // eslint-disable-next-line @typescript-eslint/no-explicit-any const bValue = safeValueForKey(b, key); const isANullable = typeof aValue == 'undefined' || aValue === null; const isBNullable = typeof bValue == 'undefined' || bValue === null; if (isANullable && isBNullable) { //both values are nullable return 0; } if (isBNullable) { // keep bValue last return -1; } if (isANullable) { // put aValue last return 1; } if (aValue.toLowerCase && bValue.toLowerCase) { return collator.compare(bValue, aValue); } if (aValue < bValue) { return 1; } else if (aValue > bValue) { return -1; } return 0; } function sortAsc(key, a, b) { if (isEmpty(key)) { return 0; } // eslint-disable-next-line @typescript-eslint/no-explicit-any const aValue = safeValueForKey(a, key); // eslint-disable-next-line @typescript-eslint/no-explicit-any const bValue = safeValueForKey(b, key); const isANullable = typeof aValue == 'undefined' || aValue === null; const isBNullable = typeof bValue == 'undefined' || bValue === null; if (isANullable && isBNullable) { //both values are nullable return 0; } if (isBNullable) { // keep bValue last return -1; } if (isANullable) { // put aValue last return 1; } if (aValue.toLowerCase && bValue.toLowerCase) { return collator.compare(aValue, bValue); } if (aValue < bValue) { return -1; } else if (aValue > bValue) { return 1; } return 0; } class SortBy { array; constructor(...args) { let [array] = args; if (typeof array.toArray === 'function') { array = array.toArray(); } this.array = [...array]; } comparator(key) { return typeof key === 'function' ? key : this.defaultSort(key); } defaultSort(sortKey) { let func = sortAsc; if (sortKey.match(':desc')) { func = sortDesc; } return (a, b) => func(sortKey.replace(/:desc|:asc/, ''), a, b); } } /** * best O(n); worst O(n^2) * If we feel like swapping with something more performant like QuickSort or MergeSort * then it should be easy * * @class BubbleSort * @extends SortBy */ class BubbleSort extends SortBy { perform(keys = []) { let swapped = false; const compFuncs = keys.map(key => this.comparator(key)); const compFunc = (a, b) => { for (let i = 0; i < compFuncs.length; i += 1) { const result = compFuncs[i]?.(a, b); if (result === 0) { continue; } return result; } return 0; }; for (let i = 1; i < this.array.length; i += 1) { for (let j = 0; j < this.array.length - i; j += 1) { const shouldSwap = normalizeToBoolean(compFunc(this.array[j + 1], this.array[j])); if (shouldSwap) { [this.array[j], this.array[j + 1]] = [this.array[j + 1], this.array[j]]; swapped = true; } } // no need to continue sort if not swapped in any inner iteration if (!swapped) { return this.array; } } } } // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents function sortBy(params) { // slice params to avoid mutating the provided params const sortParams = params.slice(); const array = asArray(sortParams.pop()); let sortKeys = sortParams; if (!array || !sortKeys || sortKeys.length === 0) { return []; } if (sortKeys.length === 1 && Array.isArray(sortKeys[0])) { sortKeys = sortKeys[0]; } const sortKlass = new BubbleSort(array); sortKlass.perform(sortKeys); return sortKlass.array; } var sortBy$1 = helper(sortBy); export { sortBy$1 as default, sortBy }; //# sourceMappingURL=sort-by.js.map