From f6d8a80361a2fba1ce069101ff52efdcc982be1d Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Thu, 18 Feb 2021 10:42:55 -0700 Subject: [PATCH] feat: support custom sorter --- README.md | 26 ++++++++++++++++++++++++++ src/__tests__/index.ts | 12 ++++++++++++ src/index.ts | 11 ++++++++--- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 612197f..14f6eae 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Feedback welcome! - [threshold: `number`](#threshold-number) - [keepDiacritics: `boolean`](#keepdiacritics-boolean) - [baseSort: `function(itemA, itemB): -1 | 0 | 1`](#basesort-functionitema-itemb--1--0--1) + - [sorter: `function(rankedItems): rankedItems`](#sorter-functionrankeditems-rankeditems) - [Recipes](#recipes) - [Match PascalCase, camelCase, snake_case, or kebab-case as words](#match-pascalcase-camelcase-snake_case-or-kebab-case-as-words) - [Match many words across multiple fields (table filtering)](#match-many-words-across-multiple-fields-table-filtering) @@ -344,6 +345,31 @@ matchSorter(list, 'apple', {baseSort: (a, b) => (a.index < b.index ? -1 : 1)}) // ['C apple', 'B apple', 'A apple'] ``` +### sorter: `function(rankedItems): rankedItems` + +_Default: +`matchedItems => matchedItems.sort((a, b) => sortRankedValues(a, b, baseSort))`_ + +By default, match-sorter uses an internal `sortRankedValues` function to sort +items after matching them. + +_You can customize the core sorting behavior by specifying a custom `sorter` +function:_ + +Disable sorting entirely: +```javascript +const list = ['appl', 'C apple', 'B apple', 'A apple', 'app', 'applebutter'] +matchSorter(list, 'apple', {sorter: rankedItems => rankedItems}) +// ['C apple', 'B apple', 'A apple', 'applebutter'] +``` + +Return the unsorted rankedItems, but in reverse order: +```javascript +const list = ['appl', 'C apple', 'B apple', 'A apple', 'app', 'applebutter'] +matchSorter(list, 'apple', {sorter: rankedItems => [...rankedItems].reverse()}) +// ['applebutter', 'A apple', 'B apple', 'C apple'] +``` + ## Recipes ### Match PascalCase, camelCase, snake_case, or kebab-case as words diff --git a/src/__tests__/index.ts b/src/__tests__/index.ts index 5e73372..dd795dd 100644 --- a/src/__tests__/index.ts +++ b/src/__tests__/index.ts @@ -495,6 +495,18 @@ const tests: Record = { ], output: [{name: 'Jen_Smith'}, {name: 'Janice_Kurtis'}], }, + 'support a custom sortRankedValues function to overriding all sorting functionality': { + input: [ + ['appl', 'C apple', 'B apple', 'A apple', 'app', 'applebutter'], + '', + { + sorter: rankedItems => { + return [...rankedItems].reverse() + }, + }, + ], + output: ['applebutter', 'app', 'A apple', 'B apple', 'C apple', 'appl'], + }, } for (const [ diff --git a/src/index.ts b/src/index.ts index 086983e..b5e4dbb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,6 +31,10 @@ interface BaseSorter { (a: RankedItem, b: RankedItem): number } +interface Sorter { + (matchItems: Array>): Array> +} + interface KeyAttributesOptions { key?: string | ValueGetterKey threshold?: Ranking @@ -48,6 +52,7 @@ interface MatchSorterOptions { threshold?: Ranking baseSort?: BaseSorter keepDiacritics?: boolean + sorter?: Sorter } type IndexableByString = Record @@ -85,11 +90,11 @@ function matchSorter( keys, threshold = rankings.MATCHES, baseSort = defaultBaseSortFn, + sorter = matchedItems => + matchedItems.sort((a, b) => sortRankedValues(a, b, baseSort)), } = options const matchedItems = items.reduce(reduceItemsToRanked, []) - return matchedItems - .sort((a, b) => sortRankedValues(a, b, baseSort)) - .map(({item}) => item) + return sorter(matchedItems).map(({item}) => item) function reduceItemsToRanked( matches: Array>,