Search for a given subsequence in a list of strings and transform the resulting list as required
MIT License
Search for a given subsequence in a list of strings and transform the resulting list as required.
Out of the box it can be made to behave a lot like the sublime text fuzzy search.
The resulting list can be transformed using chainable transforms.
Demo it here. Demo showing special character support is here.
npm install subsequence-search --save
or
bower install subsequence-search --save
Go ahead and require('subsequence-search)
in your node
program after installation.
After installation, serve:
subsequence-search.js
orsubsequence-search.min.js
out of node_modules/subsequence-search/build/
In your browser code, go ahead and use window.subsequenceSearch
to use it globally
or
If you use a UMD compatible loader like require.js
then go ahead and require('subsequence-search')
.
The
search
as well as the built-intransform
functions, all auto-curry when given an incomplete set of arguments. Therefore, you can make reusable curried versions of those methods. For example,search
that works on some fixed inputdataList
and fixed set oftransforms
but for varyingsearchString
. Cleaner, composable code should be the result.
transforms
is an object
containing transform
functions (transforms
are explained later)
transform
functions are applied in order to the data list got after matching searchString
and dataList
.dataList
is an array of string
s that you want to match against or an object
(that has no circular references) with data
and searchInProps
properties.
data
is an Array
of objectssearchInProps
is an Array
of the properties that you want to search for the searchString
in. They should be valid properties contained in the each object in the data
arraydataList = ['some string', 'some other string', 'oh look, another string'];
/* OR */
dataList = {
data: [
{id: 1, text: 'some string'},
{id: 2, text: 'some other string'},
{id: 3, text: 'oh look, another string'}
],
searchInProps: ['text']
};
/* both of the above are valid dataList inputs */
searchInProps
must only have properties that have string
datasearchString
is the string
you want to match against the dataList
search
usage example:
var subsearch = window.subsequenceSearch; //or require('subsequence-search') in node
var data1 = ['there is some fog', 'have an apple', 'omg! potato?', 'foxes are kinda cool!'];
var data2 = {
data: [
{a: 10, b: 'some text'},
{a: 10, b: 'some more text'},
{a: 200, b: 'you shall not pass?'}
],
searchInProps: ['b']
};
console.log(subsearch.search({
rank: subsearch.transforms.rank(0),
highlight: subsearch.transforms.highlight('highlightClass')
}, data1, 'fo'));
/* output */
/* [
'<span class="highlightClass">f</span><span class="highlightClass">o</span>xes are kinda cool!',
'there is some <span class="highlightClass">f</span><span class="highlightClass">o</span>g'
]
*/
/*
* Lets see another example where the dataList is an object.
* Also, let's use the noHighlight transform instead of highlight transform.
*/
console.log(subsearch.search({
rank: subsearch.transforms.rank('b'),
noHighlight: subsearch.transforms.noHighlight
}, data2, 'text'));
/* output is shown in the image below */
As you can see in the image, the input object structure is maintained and the properties that you search on are ranked (and modified if required, for e.g., by the highlight transform) in place.
You can write a custom transform to pick out only the data
property from that object if required. Example:
console.log(subsearch.search({
rank: subsearch.transforms.rank('b'),
noHighlight: subsearch.transforms.noHighlight,
pluckData: function(dataList){
return dataList.data;
}
}, data2, 'text'));
/* the output is in the image below */
transforms
is an object can hold multiple transform
functions.
It's modelled as an Object
and not an Array
for readability purposes (it helps to enforce naming of your function to explain what it does).
A transform
is a function
that accepts a dataList
and returns transformed data.
A dataList
, as mentioned before, is either:
Array
of String
s orObject
containing a data
property and a searchInProps
propertyWhen the input to search
is an array of strings, the dataList
received by a transform
function
is of the form of an array returned by String.prototype.match
.
For example:
var subsearch = window.subsequenceSearch; //or require('subsequence-search') in node
//lets say you have the following data
var data = ['there is some fog', 'have an apple', 'omg! potato?', 'foxes are kinda cool!'];
//and you do
subsearch.search({
myTransform: function(list){
console.log(list);
return list;
}
}, data, 'fo');
//then you get an array containing to arrays printed in your console
//see the image below
As you can see in the image, each item is the same as what you get when you do
'some string'.match(/^(s)(.*?)(e)(.*)$/);
i.e., a String.prototype.match
with some capturing groups.
When the input to search
is an Object
that has the same shape as a dataList
object (i.e., it has data
and searchInProps
properties), the dataList
received by a transform
is of the same shape and form as the input dataList
with its searchInProps
data modified in place (if needed).
Example:
Transforms are applied in order. This is very important to remember while writing custom transforms so that you can match the output of one to the input of another.
You can chain as many transform
functions as you want by passing them in the transforms
object to the search
call. The only requisite for chaining is that, the output of the nth transform should be in a form that is consumable by the (n+1)th transform (since they are applied in order.)
Keeping that in mind, you can do what you wish in those transform
functions to get the data in a format that is useful for your application.
subsequence-search
ships with three transform
functions for your convenience. They are:
rank
: returns a re-ordered dataList
that has the most relevant results higher in the list. It takes the following parameter:
rankByKey
- the key/property/index to rank by.
dataList
is an Array
of String
s, this can be 0
dataList
is an Object
with data
and searchInProps
, then this can be any property in the objects contained in data
arrayhighlight
: accepts a css
class and transforms the result set to encapsulate the matching letters in a span
with the given css
class
noHighlight
: returns back an array of plaintext matches
noResults
: returns a string
that the user provides as input or default string ('No results found.') when input search string isn't found in input data
These are available on the transforms
property on the object you get when you do require('subsequence-search')
i.e.,
var subsearch = window.subsequenceSearch; //or require('subsequence-search') in node
//built in transforms:
//subsearch.transforms.rank
//subsearch.transforms.highlight(classname)
//subsearch.transforms.noHighlight
var data = ['there is some fog', 'have an apple', 'omg! potato?', 'foxes are kinda cool!'];
console.log(subsearch.search({
rank: subsearch.transforms.rank(0),
highlight: subsearch.transforms.highlight('highlightClass'),
noResults: subsearch.transforms.noResults('No results found for your input.')
}, data, 'fo'));
//output
//["<span class="highlightClass">f</span><span class="highlightClass">o</span>xes are kinda cool!", "there is some <span class="highlightClass">f</span><span class="highlightClass">o</span>g"]
subsequence-search
is compatible with browsers that are ES5 compliant and Node.js > 0.10.x
.
It uses map
, reduce
, filter
, etc heavily so if you need to use subsequence-search
on older browsers, use a shim.
1.0.1
npm
website1.0.0
0.3.4
has been in production usage for quite a while, promoting it to stable0.3.4
clone
as a dependency for deep cloning, cycle detection, etc0.3.3
noResults
transform. This transform accepts a string that is displayed when no results are foundvar s = window.subsequenceSearch.search({ noResults: window.subsequenceSearch.transforms.noResults('No results found.')});
rank
transform. It now calculates grouping score correctlysearchString
with special characters ('*', '+', '(', etc) breaking subsequence-search
0.3.2
Array.prototype.sort
implemented by browser vendors0.3.1
subsequence-search
handled an empty searchString
is now fixed and should work as a user would expect it to0.3.0
Nuked my whole repo thanks to Google Drive and my idiocy and hence npm won't be able to download previous versions since technically they don't exist anymore. GOD DAMN IT! My apologies. :(
Massive rewrite to add support for dataList
to be an object with shape
var dataList = {
data: [ ...objects... ],
searchInProps: [ ...properties in objects given above... ]
};
Changed the signature for search
. transforms
object is now the first parameter. This signature, combined with the fact that search
auto-curries, you can produce a custom search function with a particular transform
sequence just once and use it whenever you need by supplying the remaining two parameters. Example:
var subsearch = window.subsequenceSearch; //or require('subsequence-search');
var dataList = {
data: [
{a: 10, 'text': 'some text'},
{a: 10, 'text': 'some more text'},
{a: 200, 'text': 'you shall not pass?'}
],
searchInProps: ['text']
};
var rankAndNohighlightSearch = subsearch.search({
rank: subsearch.transforms.rank('text'),
noHighlight: subsearch.transforms.noHighlight
});
console.log(rankAndNohighlightSearch(dataList, 'some'));
0.2.0
search
signature to search(dataList, transforms, searchString)
to enable users to curry it more effectivelybower
support0.1.4
0.1.3
index.js
0.1.2
package.json
(missing git repo)0.1.1
0.1.0
transforms