/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ type SortPropGetter = (x: T) => number | string | undefined; type Comparator = (a: T, b: T) => number; /** * create a sort comparator that sorts objects in ascending * order based on the ...getters. getters are called for each * item and return the value to compare against the other items. * * - if a getter returns undefined the item will be sorted * before all other items * - if a getter returns a string it will be compared using * `String#localeCompare` * - otherwise comparison is done using subtraction * - If the values for a getter are equal the next getter is * used to compare the items. */ export const ascending = (...getters: Array>): Comparator => (a, b) => { for (const getter of getters) { const valA = getter(a); const valB = getter(b); if (valA === valB) { continue; } if (valA === undefined) { return -1; } if (valB === undefined) { return 1; } return typeof valA === 'string' || typeof valB === 'string' ? String(valA).localeCompare(String(valB)) : valA - valB; } return 0; }; /** * create a sort comparator that sorts values in descending * order based on the ...getters * * See docs for ascending() */ export const descending = (...getters: Array>): Comparator => { const sorter = ascending(...getters); return (a, b) => sorter(b, a); }; /** * Alternate Array#includes() implementation with sane types, functions as a type guard */ export const includes = (array: T[], value: any): value is T => array.includes(value); /** * Ponyfill for Object.fromEntries() */ export const entriesToObject = (entries: Array): Record => { const object: Record = {}; for (const [key, value] of entries) { object[key] = value; } return object; };