Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support custom sorter #124

Merged
merged 1 commit into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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