diff --git a/.all-contributorsrc b/.all-contributorsrc index ef0770e..2404b0b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -104,6 +104,17 @@ "contributions": [ "code" ] + }, + { + "login": "tikotzky", + "name": "Mordy Tikotzky", + "avatar_url": "https://avatars3.githubusercontent.com/u/200528?v=4", + "profile": "https://github.com/tikotzky", + "contributions": [ + "code", + "doc", + "test" + ] } ], "repoType": "github" diff --git a/README.md b/README.md index 5af62d4..070c80a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ [![downloads][downloads-badge]][npm-stat] [![MIT License][license-badge]][license] -[![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors) [![PRs Welcome][prs-badge]][prs] [![Donate][donate-badge]][donate] [![Code of Conduct][coc-badge]][coc] @@ -54,21 +54,20 @@ To explain the ranking system, I'll use countries as an example: This ranking seems to make sense in people's minds. At least it does in mine. Feedback welcome! - -* [Getting Started](#getting-started) - * [Installation](#installation) - * [Usage](#usage) -* [Advanced options](#advanced-options) - * [keys: `[string]`](#keys-string) - * [threshold: `number`](#threshold-number) - * [keepDiacritics: `boolean`](#keepdiacritics-boolean) -* [Using ES6?](#using-es6) -* [Inspiration](#inspiration) -* [Other Solutions](#other-solutions) -* [Contributors](#contributors) -* [LICENSE](#license) +- [Getting Started](#getting-started) + - [Installation](#installation) + - [Usage](#usage) +- [Advanced options](#advanced-options) + - [keys: `[string]`](#keys-string) + - [threshold: `number`](#threshold-number) + - [keepDiacritics: `boolean`](#keepdiacritics-boolean) +- [Using ES6?](#using-es6) +- [Inspiration](#inspiration) +- [Other Solutions](#other-solutions) +- [Contributors](#contributors) +- [LICENSE](#license) @@ -160,6 +159,16 @@ matchSorter(list, 'j', {keys: [item => item.name]}) // [{name: 'Janice'}, {name: 'Jen'}] ``` +**Threshold**: You may specify an individual threshold for specific keys. A key will only match if it meets the specified threshold. _For more information regarding thresholds [see below](#threshold-number)_ + +```javascript +const list = [{name: 'Fred', color: 'Orange'}, {name: 'Jen', color: 'Red'}] +matchSorter(list, 'ed', { + keys: [{threshold: rankings.STARTS_WITH, key: 'name'}, 'color'], +}) +//[{name: 'Jen', color: 'Red'}] +``` + **Min and Max Ranking**: You may restrict specific keys to a minimum or maximum ranking by passing in an object. A key with a minimum rank will only get promoted if there is at least a simple match. ```javascript @@ -198,16 +207,16 @@ _Default: `MATCHES`_ Thresholds can be used to specify the criteria used to rank the results. Available thresholds (from top to bottom) are: -* CASE_SENSITIVE_EQUAL -* EQUAL -* STARTS_WITH -* WORD_STARTS_WITH -* STRING_CASE -* STRING_CASE_ACRONYM -* CONTAINS -* ACRONYM -* MATCHES _(default value)_ -* NO_MATCH +- CASE_SENSITIVE_EQUAL +- EQUAL +- STARTS_WITH +- WORD_STARTS_WITH +- STRING_CASE +- STRING_CASE_ACRONYM +- CONTAINS +- ACRONYM +- MATCHES _(default value)_ +- NO_MATCH ```javascript const fruit = ['orange', 'apple', 'grape', 'banana'] @@ -269,11 +278,10 @@ You might try [Fuse.js](https://github.com/krisk/Fuse). It uses advanced math fa Thanks goes to these people ([emoji key][emojis]): - | [
Kent C. Dodds](https://kentcdodds.com)
[πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=kentcdodds "Code") [πŸ“–](https://github.com/kentcdodds/match-sorter/commits?author=kentcdodds "Documentation") [πŸš‡](#infra-kentcdodds "Infrastructure (Hosting, Build-Tools, etc)") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=kentcdodds "Tests") [πŸ‘€](#review-kentcdodds "Reviewed Pull Requests") | [
Conor Hastings](http://conorhastings.com)
[πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=conorhastings "Code") [πŸ“–](https://github.com/kentcdodds/match-sorter/commits?author=conorhastings "Documentation") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=conorhastings "Tests") [πŸ‘€](#review-conorhastings "Reviewed Pull Requests") | [
Rogelio Guzman](https://github.com/rogeliog)
[πŸ“–](https://github.com/kentcdodds/match-sorter/commits?author=rogeliog "Documentation") | [
ClaudΓ©ric Demers](http://ced.io)
[πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=clauderic "Code") [πŸ“–](https://github.com/kentcdodds/match-sorter/commits?author=clauderic "Documentation") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=clauderic "Tests") | [
Kevin Davis](kevindav.us)
[πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=osfan501 "Code") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=osfan501 "Tests") | [
Denver Chen](https://github.com/nfdjps)
[πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=nfdjps "Code") [πŸ“–](https://github.com/kentcdodds/match-sorter/commits?author=nfdjps "Documentation") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=nfdjps "Tests") | [
Christian Ruigrok](http://ruigrok.info)
[πŸ›](https://github.com/kentcdodds/match-sorter/issues?q=author%3AChrisRu "Bug reports") [πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=ChrisRu "Code") [πŸ“–](https://github.com/kentcdodds/match-sorter/commits?author=ChrisRu "Documentation") | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | -| [
Hozefa](https://github.com/hozefaj)
[πŸ›](https://github.com/kentcdodds/match-sorter/issues?q=author%3Ahozefaj "Bug reports") [πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=hozefaj "Code") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=hozefaj "Tests") [πŸ€”](#ideas-hozefaj "Ideas, Planning, & Feedback") | [
pushpinder107](https://github.com/pushpinder107)
[πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=pushpinder107 "Code") | +| [
Hozefa](https://github.com/hozefaj)
[πŸ›](https://github.com/kentcdodds/match-sorter/issues?q=author%3Ahozefaj "Bug reports") [πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=hozefaj "Code") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=hozefaj "Tests") [πŸ€”](#ideas-hozefaj "Ideas, Planning, & Feedback") | [
pushpinder107](https://github.com/pushpinder107)
[πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=pushpinder107 "Code") | [
Mordy Tikotzky](https://github.com/tikotzky)
[πŸ’»](https://github.com/kentcdodds/match-sorter/commits?author=tikotzky "Code") [πŸ“–](https://github.com/kentcdodds/match-sorter/commits?author=tikotzky "Documentation") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=tikotzky "Tests") | diff --git a/src/__tests__/index.js b/src/__tests__/index.js index ba4ee0f..28d7aa0 100644 --- a/src/__tests__/index.js +++ b/src/__tests__/index.js @@ -373,6 +373,27 @@ const tests = { {tea: 'Green', alias: 'C'}, ], }, + 'only match when key meets threshold': { + input: [ + [{name: 'Fred', color: 'Orange'}, {name: 'Jen', color: 'Red'}], + 'ed', + { + keys: [{threshold: rankings.STARTS_WITH, key: 'name'}, 'color'], + }, + ], + output: [{name: 'Jen', color: 'Red'}], + }, + 'should match when key threshold is lower than the default threshold': { + input: [ + [{name: 'Fred', color: 'Orange'}, {name: 'Jen', color: 'Red'}], + 'ed', + { + keys: ['name', {threshold: rankings.CONTAINS, key: 'color'}], + threshold: rankings.STARTS_WITH, + }, + ], + output: [{name: 'Jen', color: 'Red'}], + }, } Object.keys(tests).forEach(title => { diff --git a/src/index.js b/src/index.js index a2e1ac4..ebf1e60 100644 --- a/src/index.js +++ b/src/index.js @@ -46,8 +46,13 @@ function matchSorter(items, value, options = {}) { return matchedItems.sort(sortRankedItems).map(({item}) => item) function reduceItemsToRanked(matches, item, index) { - const {rank, keyIndex} = getHighestRanking(item, keys, value, options) - if (rank >= threshold) { + const {rank, keyIndex, keyThreshold = threshold} = getHighestRanking( + item, + keys, + value, + options, + ) + if (rank >= keyThreshold) { matches.push({item, rank, index, keyIndex}) } return matches @@ -60,17 +65,21 @@ function matchSorter(items, value, options = {}) { * @param {Array} keys - the keys to get values from the item for the ranking * @param {String} value - the value to rank against * @param {Object} options - options to control the ranking - * @return {{rank: Number, keyIndex: Number}} - the highest ranking + * @return {{rank: Number, keyIndex: Number, keyThreshold: Number}} - the highest ranking */ function getHighestRanking(item, keys, value, options) { if (!keys) { - return {rank: getMatchRanking(item, value, options), keyIndex: -1} + return { + rank: getMatchRanking(item, value, options), + keyIndex: -1, + keyThreshold: options.threshold, + } } const valuesToRank = getAllValuesToRank(item, keys) return valuesToRank.reduce( - ({rank, keyIndex}, {itemValue, attributes}, i) => { + ({rank, keyIndex, keyThreshold}, {itemValue, attributes}, i) => { let newRank = getMatchRanking(itemValue, value, options) - const {minRanking, maxRanking} = attributes + const {minRanking, maxRanking, threshold} = attributes if (newRank < minRanking && newRank >= rankings.MATCHES) { newRank = minRanking } else if (newRank > maxRanking) { @@ -79,10 +88,11 @@ function getHighestRanking(item, keys, value, options) { if (newRank > rank) { rank = newRank keyIndex = i + keyThreshold = threshold } - return {rank, keyIndex} + return {rank, keyIndex, keyThreshold} }, - {rank: rankings.NO_MATCH, keyIndex: -1}, + {rank: rankings.NO_MATCH, keyIndex: -1, keyThreshold: options.threshold}, ) }