diff --git a/README.md b/README.md index eda24f3..207a54a 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,9 @@ Indicates whether comparisons should be case sensitive. --- -**includeScore** (*type*: `Boolean`, *default*: `false`) +**include** (*type*: `Array`, *default*: `[]`) -Whether the score should be included in the result set. When `true`, each result in the list will be of the form `{ item: ..., score: ... }` +An array of values that should be included from the searcher's output. When this array contains elements, each result in the list will be of the form `{ item: ..., include1: ..., include2: ... }`. For example, to include the score, you would set include to ['score'], and the result would be `{ item: ..., score: ... }` --- diff --git a/src/fuse.js b/src/fuse.js index ab65020..2aace68 100644 --- a/src/fuse.js +++ b/src/fuse.js @@ -288,12 +288,12 @@ var i, len, key, keys; // Add boolean type options - for (i = 0, keys = ['sort', 'includeScore', 'shouldSort'], len = keys.length; i < len; i++) { + for (i = 0, keys = ['sort', 'shouldSort'], len = keys.length; i < len; i++) { key = keys[i]; this.options[key] = key in options ? options[key] : Fuse.defaultOptions[key]; } // Add all other options - for (i = 0, keys = ['searchFn', 'sortFn', 'keys', 'getFn'], len = keys.length; i < len; i++) { + for (i = 0, keys = ['searchFn', 'sortFn', 'keys', 'getFn', 'include'], len = keys.length; i < len; i++) { key = keys[i]; this.options[key] = options[key] || Fuse.defaultOptions[key]; } @@ -304,9 +304,10 @@ caseSensitive: false, - // Whether the score should be included in the result set. - // When , each result in the list will be of the form: `{ item: ..., score: ... }` - includeScore: false, + // A list of values to be passed from the searcher to the result set. + // If include is set to ['score', 'highlight'], each result + // in the list will be of the form: `{ item: ..., score: ..., highlight: ... }` + include: [], // Whether to sort the result list, by score shouldSort: true, @@ -436,15 +437,6 @@ rawResults.sort(options.sortFn); } - // Helper function, here for speed-up, which returns the - // the raw item, including the score, or simply the item itself, depending - // on the specified option - var getItem = options.includeScore ? function(i) { - return rawResults[i]; - } : function(i) { - return rawResults[i].item; - }; - // Helper function, here for speed-up, which replaces the item with its value, // if the options specifies it, var replaceValue = options.id ? function(i) { @@ -453,11 +445,36 @@ return; // no-op }; + // Helper function, here for speed-up, which returns the + // item formatted based on the options. + var getItem = function(i) { + var resultItem; + + if(options.include.length > 0) // If `include` has values, put the item under result.item + { + resultItem = { + item: rawResults[i].item, + }; + + // Then include the includes + for(var i = 0; i < options.include.length; i++) + { + var includeVal = options.include[i]; + resultItem[includeVal] = rawResults[i][includeVal]; + } + } + else + { + resultItem = rawResults[i].item; + } + + return resultItem; + }; + // From the results, push into a new array only the item identifier (if specified) // of the entire item. This is because we don't want to return the , // since it contains other metadata; for (var i = 0, len = rawResults.length; i < len; i++) { - // replace the item with its value, which can be its id if the options specifies it replaceValue(i); results.push(getItem(i)); } @@ -481,4 +498,4 @@ global.Fuse = Fuse; } -})(this); \ No newline at end of file +})(this); diff --git a/src/fuse.min.js b/src/fuse.min.js index e00f47e..6bb47e0 100644 --- a/src/fuse.min.js +++ b/src/fuse.min.js @@ -17,4 +17,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -!function(t){function e(t,n){this.list=t,this.options=n=n||{};var i,o,s,r;for(i=0,r=["sort","includeScore","shouldSort"],o=r.length;o>i;i++)s=r[i],this.options[s]=s in n?n[s]:e.defaultOptions[s];for(i=0,r=["searchFn","sortFn","keys","getFn"],o=r.length;o>i;i++)s=r[i],this.options[s]=n[s]||e.defaultOptions[s]}var n=function(t,e){if(e=e||{},this.options=e,this.options.location=e.location||n.defaultOptions.location,this.options.distance="distance"in e?e.distance:n.defaultOptions.distance,this.options.threshold="threshold"in e?e.threshold:n.defaultOptions.threshold,this.options.maxPatternLength=e.maxPatternLength||n.defaultOptions.maxPatternLength,this.pattern=e.caseSensitive?t:t.toLowerCase(),this.patternLen=t.length,this.patternLen>this.options.maxPatternLength)throw new Error("Pattern length is too long");this.matchmask=1<i;)this._bitapScore(e,l+o)<=f?i=o:d=o,o=Math.floor((d-i)/2+i);for(d=o,s=Math.max(1,l-o+1),r=Math.min(l+o,c)+this.patternLen,a=Array(r+2),a[r+1]=(1<=s;n--)if(p=this.patternAlphabet[t.charAt(n-1)],a[n]=0===e?(a[n+1]<<1|1)&p:(a[n+1]<<1|1)&p|((h[n+1]|h[n])<<1|1)|h[n+1],a[n]&this.matchmask&&(g=this._bitapScore(e,n-1),f>=g)){if(f=g,u=n-1,m.push(u),!(u>l))break;s=Math.max(1,2*l-u)}if(this._bitapScore(e+1,l)>f)break;h=a}return{isMatch:u>=0,score:g}};var i=function(t,e,n){var s,r,a;if(e){a=e.indexOf("."),-1!==a?(s=e.slice(0,a),r=e.slice(a+1)):s=e;var h=t[s];if(h)if(r||"string"!=typeof h&&"number"!=typeof h)if(o.isArray(h))for(var p=0,c=h.length;c>p;p++)i(h[p],r,n);else r&&i(h,r,n);else n.push(h)}else n.push(t);return n},o={deepValue:function(t,e){return i(t,e,[])},isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)}};e.defaultOptions={id:null,caseSensitive:!1,includeScore:!1,shouldSort:!0,searchFn:n,sortFn:function(t,e){return t.score-e.score},getFn:o.deepValue,keys:[]},e.prototype.set=function(t){return this.list=t,t},e.prototype.search=function(t){var e,n,i,s,r=new this.options.searchFn(t,this.options),a=this.list,h=a.length,p=this.options,c=this.options.keys,l=c.length,f=[],u={},d=[],g=function(t,e,n){if(void 0!==t&&null!==t)if("string"==typeof t)i=r.search(t),i.isMatch&&(s=u[n],s?s.score=Math.min(s.score,i.score):(u[n]={item:e,score:i.score},f.push(u[n])));else if(o.isArray(t))for(var a=0;am;m++)g(a[m],m,m);else for(var m=0;h>m;m++)for(n=a[m],e=0;l>e;e++)g(p.getFn(n,c[e]),n,m);p.shouldSort&&f.sort(p.sortFn);for(var y=p.includeScore?function(t){return f[t]}:function(t){return f[t].item},v=p.id?function(t){f[t].item=p.getFn(f[t].item,p.id)[0]}:function(){},m=0,b=f.length;b>m;m++)v(m),d.push(y(m));return d},"object"==typeof exports?module.exports=e:"function"==typeof define&&define.amd?define(function(){return e}):t.Fuse=e}(this); \ No newline at end of file +!function(t){function e(t,n){this.list=t,this.options=n=n||{};var i,o,s,r;for(i=0,r=["sort","shouldSort"],o=r.length;o>i;i++)s=r[i],this.options[s]=s in n?n[s]:e.defaultOptions[s];for(i=0,r=["searchFn","sortFn","keys","getFn","include"],o=r.length;o>i;i++)s=r[i],this.options[s]=n[s]||e.defaultOptions[s]}var n=function(t,e){if(e=e||{},this.options=e,this.options.location=e.location||n.defaultOptions.location,this.options.distance="distance"in e?e.distance:n.defaultOptions.distance,this.options.threshold="threshold"in e?e.threshold:n.defaultOptions.threshold,this.options.maxPatternLength=e.maxPatternLength||n.defaultOptions.maxPatternLength,this.pattern=e.caseSensitive?t:t.toLowerCase(),this.patternLen=t.length,this.patternLen>this.options.maxPatternLength)throw new Error("Pattern length is too long");this.matchmask=1<i;)this._bitapScore(e,l+o)<=f?i=o:d=o,o=Math.floor((d-i)/2+i);for(d=o,s=Math.max(1,l-o+1),r=Math.min(l+o,c)+this.patternLen,a=Array(r+2),a[r+1]=(1<=s;n--)if(p=this.patternAlphabet[t.charAt(n-1)],0===e?a[n]=(a[n+1]<<1|1)&p:a[n]=(a[n+1]<<1|1)&p|((h[n+1]|h[n])<<1|1)|h[n+1],a[n]&this.matchmask&&(g=this._bitapScore(e,n-1),f>=g)){if(f=g,u=n-1,m.push(u),!(u>l))break;s=Math.max(1,2*l-u)}if(this._bitapScore(e+1,l)>f)break;h=a}return{isMatch:u>=0,score:g}};var i=function(t,e,n){var s,r,a;if(e){a=e.indexOf("."),-1!==a?(s=e.slice(0,a),r=e.slice(a+1)):s=e;var h=t[s];if(h)if(r||"string"!=typeof h&&"number"!=typeof h)if(o.isArray(h))for(var p=0,c=h.length;c>p;p++)i(h[p],r,n);else r&&i(h,r,n);else n.push(h)}else n.push(t);return n},o={deepValue:function(t,e){return i(t,e,[])},isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)}};e.defaultOptions={id:null,caseSensitive:!1,include:[],shouldSort:!0,searchFn:n,sortFn:function(t,e){return t.score-e.score},getFn:o.deepValue,keys:[]},e.prototype.set=function(t){return this.list=t,t},e.prototype.search=function(t){var e,n,i,s,r=new this.options.searchFn(t,this.options),a=this.list,h=a.length,p=this.options,c=this.options.keys,l=c.length,f=[],u={},d=[],g=function(t,e,n){if(void 0!==t&&null!==t)if("string"==typeof t)i=r.search(t),i.isMatch&&(s=u[n],s?s.score=Math.min(s.score,i.score):(u[n]={item:e,score:i.score},f.push(u[n])));else if(o.isArray(t))for(var a=0;am;m++)g(a[m],m,m);else for(var m=0;h>m;m++)for(n=a[m],e=0;l>e;e++)g(p.getFn(n,c[e]),n,m);p.shouldSort&&f.sort(p.sortFn);for(var v=p.id?function(t){f[t].item=p.getFn(f[t].item,p.id)[0]}:function(){},y=function(t){var e;if(p.include.length>0){e={item:f[t].item};for(var t=0;tm;m++)v(m),d.push(y(m));return d},"object"==typeof exports?module.exports=e:"function"==typeof define&&define.amd?define(function(){return e}):t.Fuse=e}(this); \ No newline at end of file diff --git a/test/fuse-test.js b/test/fuse-test.js index 095e01a..561e4d9 100644 --- a/test/fuse-test.js +++ b/test/fuse-test.js @@ -234,7 +234,7 @@ vows.describe('Include score in result list: ["Apple", "Orange", "Banana"]').add topic: function() { var fruits = ["Apple", "Orange", "Banana"]; var fuse = new Fuse(fruits, { - includeScore: true + include: ['score'] }); return fuse; }, @@ -318,7 +318,7 @@ vows.describe('Include both ID and score in results list').addBatch({ var options = { keys: ["title", "author"], id: "ISBN", - includeScore: true + include: ['score'] } var fuse = new Fuse(books, options) return fuse; @@ -356,7 +356,7 @@ vows.describe('Search when IDs are numbers').addBatch({ var options = { keys: ["title", "author"], id: "ISBN", - includeScore: true + include: ['score'] } var fuse = new Fuse(books, options) return fuse;