Skip to content

Commit

Permalink
feat: support custom sorter (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
tannerlinsley authored Feb 18, 2021
1 parent d54584d commit 9d8e7e9
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions src/__tests__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,18 @@ const tests: Record<string, TestCase> = {
],
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 [
Expand Down
11 changes: 8 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ interface BaseSorter<ItemType> {
(a: RankedItem<ItemType>, b: RankedItem<ItemType>): number
}

interface Sorter<ItemType> {
(matchItems: Array<RankedItem<ItemType>>): Array<RankedItem<ItemType>>
}

interface KeyAttributesOptions<ItemType> {
key?: string | ValueGetterKey<ItemType>
threshold?: Ranking
Expand All @@ -48,6 +52,7 @@ interface MatchSorterOptions<ItemType = unknown> {
threshold?: Ranking
baseSort?: BaseSorter<ItemType>
keepDiacritics?: boolean
sorter?: Sorter<ItemType>
}
type IndexableByString = Record<string, unknown>

Expand Down Expand Up @@ -85,11 +90,11 @@ function matchSorter<ItemType = string>(
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<RankedItem<ItemType>>,
Expand Down

0 comments on commit 9d8e7e9

Please sign in to comment.