lunr
Advanced tools
Comparing version 0.3.3 to 0.4.0
{ | ||
"name": "lunr.js", | ||
"version": "0.3.3", | ||
"version": "0.4.0", | ||
"main": "lunr.js", | ||
"ignore": [ | ||
"tests/", | ||
"perf/", | ||
"build/", | ||
@@ -8,0 +9,0 @@ "docs/" |
105
lib/index.js
@@ -20,6 +20,37 @@ /*! | ||
this.corpusTokens = new lunr.SortedSet | ||
this.eventEmitter = new lunr.EventEmitter | ||
this._idfCache = {} | ||
this.on('add', 'remove', 'update', (function () { | ||
this._idfCache = {} | ||
}).bind(this)) | ||
} | ||
/** | ||
* Bind a handler to events being emitted by the index. | ||
* | ||
* The handler can be bound to many events at the same time. | ||
* | ||
* @param {String} [eventName] The name(s) of events to bind the function to. | ||
* @param {Function} handler The serialised set to load. | ||
* @memberOf Index | ||
*/ | ||
lunr.Index.prototype.on = function () { | ||
var args = Array.prototype.slice.call(arguments) | ||
return this.eventEmitter.addListener.apply(this.eventEmitter, args) | ||
} | ||
/** | ||
* Removes a handler from an event being emitted by the index. | ||
* | ||
* @param {String} eventName The name of events to remove the function from. | ||
* @param {Function} handler The serialised set to load. | ||
* @memberOf Index | ||
*/ | ||
lunr.Index.prototype.off = function (name, fn) { | ||
return this.eventEmitter.removeListener(name, fn) | ||
} | ||
/** | ||
* Loads a previously serialised index. | ||
@@ -87,2 +118,3 @@ * | ||
* documents in the index. | ||
* @param {Boolean} emitEvent Whether to emit add events, defaults to true | ||
* @returns {lunr.Index} | ||
@@ -103,9 +135,15 @@ * @memberOf Index | ||
* | ||
* An 'add' event is emitted with the document that has been added and the index | ||
* the document has been added to. This event can be silenced by passing false | ||
* as the second argument to add. | ||
* | ||
* @param {Object} doc The document to add to the index. | ||
* @param {Boolean} emitEvent Whether or not to emit events, default true. | ||
* @memberOf Index | ||
*/ | ||
lunr.Index.prototype.add = function (doc) { | ||
lunr.Index.prototype.add = function (doc, emitEvent) { | ||
var docTokens = {}, | ||
allDocumentTokens = new lunr.SortedSet, | ||
docRef = doc[this._ref] | ||
docRef = doc[this._ref], | ||
emitEvent = emitEvent === undefined ? true : emitEvent | ||
@@ -136,2 +174,4 @@ this._fields.forEach(function (field) { | ||
}; | ||
if (emitEvent) this.eventEmitter.emit('add', doc, this) | ||
} | ||
@@ -149,7 +189,13 @@ | ||
* | ||
* A 'remove' event is emitted with the document that has been removed and the index | ||
* the document has been removed from. This event can be silenced by passing false | ||
* as the second argument to remove. | ||
* | ||
* @param {Object} doc The document to remove from the index. | ||
* @param {Boolean} emitEvent Whether to emit remove events, defaults to true | ||
* @memberOf Index | ||
*/ | ||
lunr.Index.prototype.remove = function (doc) { | ||
var docRef = doc[this._ref] | ||
lunr.Index.prototype.remove = function (doc, emitEvent) { | ||
var docRef = doc[this._ref], | ||
emitEvent = emitEvent === undefined ? true : emitEvent | ||
@@ -165,2 +211,4 @@ if (!this.documentStore.has(docRef)) return | ||
}, this) | ||
if (emitEvent) this.eventEmitter.emit('remove', doc, this) | ||
} | ||
@@ -177,3 +225,9 @@ | ||
* | ||
* An 'update' event is emitted with the document that has been updated and the index. | ||
* This event can be silenced by passing false as the second argument to update. Only | ||
* an update event will be fired, the 'add' and 'remove' events of the underlying calls | ||
* are silenced. | ||
* | ||
* @param {Object} doc The document to update in the index. | ||
* @param {Boolean} emitEvent Whether to emit update events, defaults to true | ||
* @see Index.prototype.remove | ||
@@ -183,5 +237,9 @@ * @see Index.prototype.add | ||
*/ | ||
lunr.Index.prototype.update = function (doc) { | ||
this.remove(doc) | ||
this.add(doc) | ||
lunr.Index.prototype.update = function (doc, emitEvent) { | ||
var emitEvent = emitEvent === undefined ? true : emitEvent | ||
this.remove(doc, false) | ||
this.add(doc, false) | ||
if (emitEvent) this.eventEmitter.emit('update', doc, this) | ||
} | ||
@@ -198,9 +256,12 @@ | ||
lunr.Index.prototype.idf = function (term) { | ||
var documentFrequency = Object.keys(this.tokenStore.get(term)).length | ||
if (this._idfCache[term]) return this._idfCache[term] | ||
if (documentFrequency === 0) { | ||
return 1 | ||
} else { | ||
return 1 + Math.log(this.tokenStore.length / documentFrequency) | ||
var documentFrequency = this.tokenStore.count(term), | ||
idf = 1 | ||
if (documentFrequency > 0) { | ||
idf = 1 + Math.log(this.tokenStore.length / documentFrequency) | ||
} | ||
return this._idfCache[term] = idf | ||
} | ||
@@ -234,3 +295,3 @@ | ||
var queryTokens = this.pipeline.run(lunr.tokenizer(query)), | ||
queryArr = new Array (this.corpusTokens.length), | ||
queryArr = lunr.utils.zeroFillArray(this.corpusTokens.length), | ||
documentSets = [], | ||
@@ -253,9 +314,17 @@ fieldBoosts = this._fields.reduce(function (memo, f) { return memo + f.boost }, 0) | ||
idf = self.idf(key), | ||
exactMatchBoost = (key === token ? 10 : 1), | ||
similarityBoost = 1, | ||
set = new lunr.SortedSet | ||
// if the expanded key is not an exact match to the token then | ||
// penalise the score for this key by how different the key is | ||
// to the token. | ||
if (key !== token) { | ||
var diff = Math.max(3, key.length - token.length) | ||
similarityBoost = 1 / Math.log(diff) | ||
} | ||
// calculate the query tf-idf score for this token | ||
// applying an exactMatchBoost to ensure these rank | ||
// higher than expanded terms | ||
if (pos > -1) queryArr[pos] = tf * idf * exactMatchBoost | ||
// applying an similarityBoost to ensure exact matches | ||
// these rank higher than expanded terms | ||
if (pos > -1) queryArr[pos] = tf * idf * similarityBoost | ||
@@ -303,3 +372,3 @@ // add all the documents that have this key into a set | ||
documentTokensLength = documentTokens.length, | ||
documentArr = new Array (this.corpusTokens.length) | ||
documentArr = lunr.utils.zeroFillArray(this.corpusTokens.length) | ||
@@ -306,0 +375,0 @@ for (var i = 0; i < documentTokensLength; i++) { |
@@ -25,2 +25,3 @@ /*! | ||
lunr.stopWordFilter.stopWords.elements = [ | ||
"", | ||
"a", | ||
@@ -27,0 +28,0 @@ "able", |
@@ -73,14 +73,14 @@ /*! | ||
*/ | ||
lunr.TokenStore.prototype.has = function (token, root) { | ||
var root = root || this.root, | ||
key = token[0], | ||
rest = token.slice(1) | ||
lunr.TokenStore.prototype.has = function (token) { | ||
if (!token) return false | ||
if (!(key in root)) return false | ||
var node = this.root | ||
if (rest.length === 0) { | ||
return true | ||
} else { | ||
return this.has(rest, root[key]) | ||
for (var i = 0; i < token.length; i++) { | ||
if (!node[token[i]]) return false | ||
node = node[token[i]] | ||
} | ||
return true | ||
} | ||
@@ -100,14 +100,14 @@ | ||
*/ | ||
lunr.TokenStore.prototype.getNode = function (token, root) { | ||
var root = root || this.root, | ||
key = token[0], | ||
rest = token.slice(1) | ||
lunr.TokenStore.prototype.getNode = function (token) { | ||
if (!token) return {} | ||
if (!(key in root)) return {} | ||
var node = this.root | ||
if (rest.length === 0) { | ||
return root[key] | ||
} else { | ||
return this.getNode(rest, root[key]) | ||
for (var i = 0; i < token.length; i++) { | ||
if (!node[token[i]]) return {} | ||
node = node[token[i]] | ||
} | ||
return node | ||
} | ||
@@ -130,2 +130,6 @@ | ||
lunr.TokenStore.prototype.count = function (token, root) { | ||
return Object.keys(this.get(token, root)).length | ||
} | ||
/** | ||
@@ -143,14 +147,12 @@ * Remove the document identified by ref from the token in the store. | ||
*/ | ||
lunr.TokenStore.prototype.remove = function (token, ref, root) { | ||
var root = root || this.root, | ||
key = token[0], | ||
rest = token.slice(1) | ||
lunr.TokenStore.prototype.remove = function (token, ref) { | ||
if (!token) return | ||
var node = this.root | ||
if (!(key in root)) return | ||
for (var i = 0; i < token.length; i++) { | ||
if (!(token[i] in node)) return | ||
node = node[token[i]] | ||
} | ||
if (rest.length === 0) { | ||
delete root[key].docs[ref] | ||
} else { | ||
return this.remove(rest, ref, root[key]) | ||
} | ||
delete node.docs[ref] | ||
} | ||
@@ -157,0 +159,0 @@ |
@@ -24,1 +24,20 @@ /*! | ||
})(this) | ||
/** | ||
* Returns a zero filled array of the length specified. | ||
* | ||
* @param {Number} length The number of zeros required. | ||
* @returns {Array} | ||
* @memberOf Utils | ||
*/ | ||
lunr.utils.zeroFillArray = (function () { | ||
var zeros = [0] | ||
return function (length) { | ||
while (zeros.length < length) { | ||
zeros = zeros.concat(zeros) | ||
} | ||
return zeros.slice(0, length) | ||
} | ||
})() |
@@ -15,6 +15,2 @@ /*! | ||
this.elements = elements | ||
for (var i = 0; i < elements.length; i++) { | ||
if (!(i in this.elements)) this.elements[i] = 0 | ||
} | ||
} | ||
@@ -21,0 +17,0 @@ |
273
lunr.js
/** | ||
* lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.3.3 | ||
* lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.4.0 | ||
* Copyright (C) 2013 Oliver Nightingale | ||
@@ -53,3 +53,3 @@ * MIT Licensed | ||
lunr.version = "0.3.3" | ||
lunr.version = "0.4.0" | ||
@@ -82,3 +82,104 @@ if (typeof module !== 'undefined') { | ||
})(this) | ||
/** | ||
* Returns a zero filled array of the length specified. | ||
* | ||
* @param {Number} length The number of zeros required. | ||
* @returns {Array} | ||
* @memberOf Utils | ||
*/ | ||
lunr.utils.zeroFillArray = (function () { | ||
var zeros = [0] | ||
return function (length) { | ||
while (zeros.length < length) { | ||
zeros = zeros.concat(zeros) | ||
} | ||
return zeros.slice(0, length) | ||
} | ||
})() | ||
/*! | ||
* lunr.EventEmitter | ||
* Copyright (C) 2013 Oliver Nightingale | ||
*/ | ||
/** | ||
* lunr.EventEmitter is an event emitter for lunr. It manages adding and removing event handlers and triggering events and their handlers. | ||
* | ||
* @constructor | ||
*/ | ||
lunr.EventEmitter = function () { | ||
this.events = {} | ||
} | ||
/** | ||
* Binds a handler function to a specific event(s). | ||
* | ||
* Can bind a single function to many different events in one call. | ||
* | ||
* @param {String} [eventName] The name(s) of events to bind this function to. | ||
* @param {Function} handler The function to call when an event is fired. | ||
* @memberOf EventEmitter | ||
*/ | ||
lunr.EventEmitter.prototype.addListener = function () { | ||
var args = Array.prototype.slice.call(arguments), | ||
fn = args.pop(), | ||
names = args | ||
if (typeof fn !== "function") throw new TypeError ("last argument must be a function") | ||
names.forEach(function (name) { | ||
if (!this.hasHandler(name)) this.events[name] = [] | ||
this.events[name].push(fn) | ||
}, this) | ||
} | ||
/** | ||
* Removes a handler function from a specific event. | ||
* | ||
* @param {String} eventName The name of the event to remove this function from. | ||
* @param {Function} handler The function to remove from an event. | ||
* @memberOf EventEmitter | ||
*/ | ||
lunr.EventEmitter.prototype.removeListener = function (name, fn) { | ||
if (!this.hasHandler(name)) return | ||
var fnIndex = this.events[name].indexOf(fn) | ||
this.events[name].splice(fnIndex, 1) | ||
if (!this.events[name].length) delete this.events[name] | ||
} | ||
/** | ||
* Calls all functions bound to the given event. | ||
* | ||
* Additional data can be passed to the event handler as arguments to `emit` | ||
* after the event name. | ||
* | ||
* @param {String} eventName The name of the event to emit. | ||
* @memberOf EventEmitter | ||
*/ | ||
lunr.EventEmitter.prototype.emit = function (name) { | ||
if (!this.hasHandler(name)) return | ||
var args = Array.prototype.slice.call(arguments, 1) | ||
this.events[name].forEach(function (fn) { | ||
fn.apply(undefined, args) | ||
}) | ||
} | ||
/** | ||
* Checks whether a handler has ever been stored against an event. | ||
* | ||
* @param {String} eventName The name of the event to check. | ||
* @private | ||
* @memberOf EventEmitter | ||
*/ | ||
lunr.EventEmitter.prototype.hasHandler = function (name) { | ||
return name in this.events | ||
} | ||
/*! | ||
* lunr.tokenizer | ||
@@ -337,6 +438,2 @@ * Copyright (C) 2013 Oliver Nightingale | ||
this.elements = elements | ||
for (var i = 0; i < elements.length; i++) { | ||
if (!(i in this.elements)) this.elements[i] = 0 | ||
} | ||
} | ||
@@ -665,6 +762,37 @@ | ||
this.corpusTokens = new lunr.SortedSet | ||
this.eventEmitter = new lunr.EventEmitter | ||
this._idfCache = {} | ||
this.on('add', 'remove', 'update', (function () { | ||
this._idfCache = {} | ||
}).bind(this)) | ||
} | ||
/** | ||
* Bind a handler to events being emitted by the index. | ||
* | ||
* The handler can be bound to many events at the same time. | ||
* | ||
* @param {String} [eventName] The name(s) of events to bind the function to. | ||
* @param {Function} handler The serialised set to load. | ||
* @memberOf Index | ||
*/ | ||
lunr.Index.prototype.on = function () { | ||
var args = Array.prototype.slice.call(arguments) | ||
return this.eventEmitter.addListener.apply(this.eventEmitter, args) | ||
} | ||
/** | ||
* Removes a handler from an event being emitted by the index. | ||
* | ||
* @param {String} eventName The name of events to remove the function from. | ||
* @param {Function} handler The serialised set to load. | ||
* @memberOf Index | ||
*/ | ||
lunr.Index.prototype.off = function (name, fn) { | ||
return this.eventEmitter.removeListener(name, fn) | ||
} | ||
/** | ||
* Loads a previously serialised index. | ||
@@ -732,2 +860,3 @@ * | ||
* documents in the index. | ||
* @param {Boolean} emitEvent Whether to emit add events, defaults to true | ||
* @returns {lunr.Index} | ||
@@ -748,9 +877,15 @@ * @memberOf Index | ||
* | ||
* An 'add' event is emitted with the document that has been added and the index | ||
* the document has been added to. This event can be silenced by passing false | ||
* as the second argument to add. | ||
* | ||
* @param {Object} doc The document to add to the index. | ||
* @param {Boolean} emitEvent Whether or not to emit events, default true. | ||
* @memberOf Index | ||
*/ | ||
lunr.Index.prototype.add = function (doc) { | ||
lunr.Index.prototype.add = function (doc, emitEvent) { | ||
var docTokens = {}, | ||
allDocumentTokens = new lunr.SortedSet, | ||
docRef = doc[this._ref] | ||
docRef = doc[this._ref], | ||
emitEvent = emitEvent === undefined ? true : emitEvent | ||
@@ -781,2 +916,4 @@ this._fields.forEach(function (field) { | ||
}; | ||
if (emitEvent) this.eventEmitter.emit('add', doc, this) | ||
} | ||
@@ -794,7 +931,13 @@ | ||
* | ||
* A 'remove' event is emitted with the document that has been removed and the index | ||
* the document has been removed from. This event can be silenced by passing false | ||
* as the second argument to remove. | ||
* | ||
* @param {Object} doc The document to remove from the index. | ||
* @param {Boolean} emitEvent Whether to emit remove events, defaults to true | ||
* @memberOf Index | ||
*/ | ||
lunr.Index.prototype.remove = function (doc) { | ||
var docRef = doc[this._ref] | ||
lunr.Index.prototype.remove = function (doc, emitEvent) { | ||
var docRef = doc[this._ref], | ||
emitEvent = emitEvent === undefined ? true : emitEvent | ||
@@ -810,2 +953,4 @@ if (!this.documentStore.has(docRef)) return | ||
}, this) | ||
if (emitEvent) this.eventEmitter.emit('remove', doc, this) | ||
} | ||
@@ -822,3 +967,9 @@ | ||
* | ||
* An 'update' event is emitted with the document that has been updated and the index. | ||
* This event can be silenced by passing false as the second argument to update. Only | ||
* an update event will be fired, the 'add' and 'remove' events of the underlying calls | ||
* are silenced. | ||
* | ||
* @param {Object} doc The document to update in the index. | ||
* @param {Boolean} emitEvent Whether to emit update events, defaults to true | ||
* @see Index.prototype.remove | ||
@@ -828,5 +979,9 @@ * @see Index.prototype.add | ||
*/ | ||
lunr.Index.prototype.update = function (doc) { | ||
this.remove(doc) | ||
this.add(doc) | ||
lunr.Index.prototype.update = function (doc, emitEvent) { | ||
var emitEvent = emitEvent === undefined ? true : emitEvent | ||
this.remove(doc, false) | ||
this.add(doc, false) | ||
if (emitEvent) this.eventEmitter.emit('update', doc, this) | ||
} | ||
@@ -843,9 +998,12 @@ | ||
lunr.Index.prototype.idf = function (term) { | ||
var documentFrequency = Object.keys(this.tokenStore.get(term)).length | ||
if (this._idfCache[term]) return this._idfCache[term] | ||
if (documentFrequency === 0) { | ||
return 1 | ||
} else { | ||
return 1 + Math.log(this.tokenStore.length / documentFrequency) | ||
var documentFrequency = this.tokenStore.count(term), | ||
idf = 1 | ||
if (documentFrequency > 0) { | ||
idf = 1 + Math.log(this.tokenStore.length / documentFrequency) | ||
} | ||
return this._idfCache[term] = idf | ||
} | ||
@@ -879,3 +1037,3 @@ | ||
var queryTokens = this.pipeline.run(lunr.tokenizer(query)), | ||
queryArr = new Array (this.corpusTokens.length), | ||
queryArr = lunr.utils.zeroFillArray(this.corpusTokens.length), | ||
documentSets = [], | ||
@@ -898,9 +1056,17 @@ fieldBoosts = this._fields.reduce(function (memo, f) { return memo + f.boost }, 0) | ||
idf = self.idf(key), | ||
exactMatchBoost = (key === token ? 10 : 1), | ||
similarityBoost = 1, | ||
set = new lunr.SortedSet | ||
// if the expanded key is not an exact match to the token then | ||
// penalise the score for this key by how different the key is | ||
// to the token. | ||
if (key !== token) { | ||
var diff = Math.max(3, key.length - token.length) | ||
similarityBoost = 1 / Math.log(diff) | ||
} | ||
// calculate the query tf-idf score for this token | ||
// applying an exactMatchBoost to ensure these rank | ||
// higher than expanded terms | ||
if (pos > -1) queryArr[pos] = tf * idf * exactMatchBoost | ||
// applying an similarityBoost to ensure exact matches | ||
// these rank higher than expanded terms | ||
if (pos > -1) queryArr[pos] = tf * idf * similarityBoost | ||
@@ -948,3 +1114,3 @@ // add all the documents that have this key into a set | ||
documentTokensLength = documentTokens.length, | ||
documentArr = new Array (this.corpusTokens.length) | ||
documentArr = lunr.utils.zeroFillArray(this.corpusTokens.length) | ||
@@ -1290,2 +1456,3 @@ for (var i = 0; i < documentTokensLength; i++) { | ||
lunr.stopWordFilter.stopWords.elements = [ | ||
"", | ||
"a", | ||
@@ -1485,14 +1652,14 @@ "able", | ||
*/ | ||
lunr.TokenStore.prototype.has = function (token, root) { | ||
var root = root || this.root, | ||
key = token[0], | ||
rest = token.slice(1) | ||
lunr.TokenStore.prototype.has = function (token) { | ||
if (!token) return false | ||
if (!(key in root)) return false | ||
var node = this.root | ||
if (rest.length === 0) { | ||
return true | ||
} else { | ||
return this.has(rest, root[key]) | ||
for (var i = 0; i < token.length; i++) { | ||
if (!node[token[i]]) return false | ||
node = node[token[i]] | ||
} | ||
return true | ||
} | ||
@@ -1512,14 +1679,14 @@ | ||
*/ | ||
lunr.TokenStore.prototype.getNode = function (token, root) { | ||
var root = root || this.root, | ||
key = token[0], | ||
rest = token.slice(1) | ||
lunr.TokenStore.prototype.getNode = function (token) { | ||
if (!token) return {} | ||
if (!(key in root)) return {} | ||
var node = this.root | ||
if (rest.length === 0) { | ||
return root[key] | ||
} else { | ||
return this.getNode(rest, root[key]) | ||
for (var i = 0; i < token.length; i++) { | ||
if (!node[token[i]]) return {} | ||
node = node[token[i]] | ||
} | ||
return node | ||
} | ||
@@ -1542,2 +1709,6 @@ | ||
lunr.TokenStore.prototype.count = function (token, root) { | ||
return Object.keys(this.get(token, root)).length | ||
} | ||
/** | ||
@@ -1555,14 +1726,12 @@ * Remove the document identified by ref from the token in the store. | ||
*/ | ||
lunr.TokenStore.prototype.remove = function (token, ref, root) { | ||
var root = root || this.root, | ||
key = token[0], | ||
rest = token.slice(1) | ||
lunr.TokenStore.prototype.remove = function (token, ref) { | ||
if (!token) return | ||
var node = this.root | ||
if (!(key in root)) return | ||
for (var i = 0; i < token.length; i++) { | ||
if (!(token[i] in node)) return | ||
node = node[token[i]] | ||
} | ||
if (rest.length === 0) { | ||
delete root[key].docs[ref] | ||
} else { | ||
return this.remove(rest, ref, root[key]) | ||
} | ||
delete node.docs[ref] | ||
} | ||
@@ -1569,0 +1738,0 @@ |
/** | ||
* lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.3.3 | ||
* lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.4.0 | ||
* Copyright (C) 2013 Oliver Nightingale | ||
@@ -7,2 +7,2 @@ * MIT Licensed | ||
*/ | ||
var lunr=function(e){var t=new lunr.Index;return t.pipeline.add(lunr.stopWordFilter,lunr.stemmer),e&&e.call(t,t),t};lunr.version="0.3.3","undefined"!=typeof module&&(module.exports=lunr),lunr.utils={},lunr.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),lunr.tokenizer=function(e){if(!e)return[];if(Array.isArray(e))return e;for(var e=e.replace(/^\s+/,""),t=e.length-1;t>=0;t--)if(/\S/.test(e.charAt(t))){e=e.substring(0,t+1);break}return e.split(/\s+/).map(function(e){return e.replace(/^\W+/,"").replace(/\W+$/,"").toLowerCase()})},lunr.Pipeline=function(){this._stack=[]},lunr.Pipeline.registeredFunctions={},lunr.Pipeline.registerFunction=function(e,t){t in this.registeredFunctions&&lunr.utils.warn("Overwriting existing registered function: "+t),e.label=t,lunr.Pipeline.registeredFunctions[e.label]=e},lunr.Pipeline.warnIfFunctionNotRegistered=function(e){var t=e.label&&e.label in this.registeredFunctions;t||lunr.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},lunr.Pipeline.load=function(e){var t=new lunr.Pipeline;return e.forEach(function(e){var n=lunr.Pipeline.registeredFunctions[e];if(!n)throw Error("Cannot load un-registered function: "+e);t.add(n)}),t},lunr.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){lunr.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},lunr.Pipeline.prototype.after=function(e,t){lunr.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e)+1;this._stack.splice(n,0,t)},lunr.Pipeline.prototype.before=function(e,t){lunr.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e);this._stack.splice(n,0,t)},lunr.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);this._stack.splice(t,1)},lunr.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,r=this._stack.length,o=0;n>o;o++){for(var i=e[o],s=0;r>s&&(i=this._stack[s](i,o,e),void 0!==i);s++);void 0!==i&&t.push(i)}return t},lunr.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return lunr.Pipeline.warnIfFunctionNotRegistered(e),e.label})},lunr.Vector=function(e){this.elements=e;for(var t=0;e.length>t;t++)t in this.elements||(this.elements[t]=0)},lunr.Vector.prototype.magnitude=function(){if(this._magnitude)return this._magnitude;for(var e,t=0,n=this.elements,r=n.length,o=0;r>o;o++)e=n[o],t+=e*e;return this._magnitude=Math.sqrt(t)},lunr.Vector.prototype.dot=function(e){for(var t=this.elements,n=e.elements,r=t.length,o=0,i=0;r>i;i++)o+=t[i]*n[i];return o},lunr.Vector.prototype.similarity=function(e){return this.dot(e)/(this.magnitude()*e.magnitude())},lunr.Vector.prototype.toArray=function(){return this.elements},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){Array.prototype.slice.call(arguments).forEach(function(e){~this.indexOf(e)||this.elements.splice(this.locationFor(e),0,e)},this),this.length=this.elements.length},lunr.SortedSet.prototype.toArray=function(){return this.elements.slice()},lunr.SortedSet.prototype.map=function(e,t){return this.elements.map(e,t)},lunr.SortedSet.prototype.forEach=function(e,t){return this.elements.forEach(e,t)},lunr.SortedSet.prototype.indexOf=function(e,t,n){var t=t||0,n=n||this.elements.length,r=n-t,o=t+Math.floor(r/2),i=this.elements[o];return 1>=r?i===e?o:-1:e>i?this.indexOf(e,o,n):i>e?this.indexOf(e,t,o):i===e?o:void 0},lunr.SortedSet.prototype.locationFor=function(e,t,n){var t=t||0,n=n||this.elements.length,r=n-t,o=t+Math.floor(r/2),i=this.elements[o];if(1>=r){if(i>e)return o;if(e>i)return o+1}return e>i?this.locationFor(e,o,n):i>e?this.locationFor(e,t,o):void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,r=0,o=this.length,i=e.length,s=this.elements,l=e.elements;;){if(n>o-1||r>i-1)break;s[n]!==l[r]?s[n]<l[r]?n++:s[n]>l[r]&&r++:(t.add(s[n]),n++,r++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,r;return this.length>=e.length?(t=this,n=e):(t=e,n=this),r=t.clone(),r.add.apply(r,n.toArray()),r},lunr.SortedSet.prototype.toJSON=function(){return this.toArray()},lunr.Index=function(){this._fields=[],this._ref="id",this.pipeline=new lunr.Pipeline,this.documentStore=new lunr.Store,this.tokenStore=new lunr.TokenStore,this.corpusTokens=new lunr.SortedSet},lunr.Index.load=function(e){e.version!==lunr.version&&lunr.utils.warn("version mismatch: current "+lunr.version+" importing "+e.version);var t=new this;return t._fields=e.fields,t._ref=e.ref,t.documentStore=lunr.Store.load(e.documentStore),t.tokenStore=lunr.TokenStore.load(e.tokenStore),t.corpusTokens=lunr.SortedSet.load(e.corpusTokens),t.pipeline=lunr.Pipeline.load(e.pipeline),t},lunr.Index.prototype.field=function(e,t){var t=t||{},n={name:e,boost:t.boost||1};return this._fields.push(n),this},lunr.Index.prototype.ref=function(e){return this._ref=e,this},lunr.Index.prototype.add=function(e){var t={},n=new lunr.SortedSet,r=e[this._ref];this._fields.forEach(function(r){var o=this.pipeline.run(lunr.tokenizer(e[r.name]));t[r.name]=o,lunr.SortedSet.prototype.add.apply(n,o)},this),this.documentStore.set(r,n),lunr.SortedSet.prototype.add.apply(this.corpusTokens,n.toArray());for(var o=0;n.length>o;o++){var i=n.elements[o],s=this._fields.reduce(function(e,n){var r=t[n.name].length;if(!r)return e;var o=t[n.name].filter(function(e){return e===i}).length;return e+o/r*n.boost},0);this.tokenStore.add(i,{ref:r,tf:s})}},lunr.Index.prototype.remove=function(e){var t=e[this._ref];if(this.documentStore.has(t)){var n=this.documentStore.get(t);this.documentStore.remove(t),n.forEach(function(e){this.tokenStore.remove(e,t)},this)}},lunr.Index.prototype.update=function(e){this.remove(e),this.add(e)},lunr.Index.prototype.idf=function(e){var t=Object.keys(this.tokenStore.get(e)).length;return 0===t?1:1+Math.log(this.tokenStore.length/t)},lunr.Index.prototype.search=function(e){var t=this.pipeline.run(lunr.tokenizer(e)),n=Array(this.corpusTokens.length),r=[],o=this._fields.reduce(function(e,t){return e+t.boost},0),i=t.some(function(e){return this.tokenStore.has(e)},this);if(!i)return[];t.forEach(function(e,t,i){var s=1/i.length*this._fields.length*o,l=this,u=this.tokenStore.expand(e).reduce(function(t,r){var o=l.corpusTokens.indexOf(r),i=l.idf(r),u=r===e?10:1,a=new lunr.SortedSet;return o>-1&&(n[o]=s*i*u),Object.keys(l.tokenStore.get(r)).forEach(function(e){a.add(e)}),t.union(a)},new lunr.SortedSet);r.push(u)},this);var s=r.reduce(function(e,t){return e.intersect(t)}),l=new lunr.Vector(n);return s.map(function(e){return{ref:e,score:l.similarity(this.documentVector(e))}},this).sort(function(e,t){return t.score-e.score})},lunr.Index.prototype.documentVector=function(e){for(var t=this.documentStore.get(e),n=t.length,r=Array(this.corpusTokens.length),o=0;n>o;o++){var i=t.elements[o],s=this.tokenStore.get(i)[e].tf,l=this.idf(i);r[this.corpusTokens.indexOf(i)]=s*l}return new lunr.Vector(r)},lunr.Index.prototype.toJSON=function(){return{version:lunr.version,fields:this._fields,ref:this._ref,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},lunr.Store=function(){this.store={},this.length=0},lunr.Store.load=function(e){var t=new this;return t.length=e.length,t.store=Object.keys(e.store).reduce(function(t,n){return t[n]=lunr.SortedSet.load(e.store[n]),t},{}),t},lunr.Store.prototype.set=function(e,t){this.store[e]=t,this.length=Object.keys(this.store).length},lunr.Store.prototype.get=function(e){return this.store[e]},lunr.Store.prototype.has=function(e){return e in this.store},lunr.Store.prototype.remove=function(e){this.has(e)&&(delete this.store[e],this.length--)},lunr.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},lunr.stemmer=function(){var e={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},t={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",r="[aeiouy]",o=n+"[^aeiouy]*",i=r+"[aeiou]*",s="^("+o+")?"+i+o,l="^("+o+")?"+i+o+"("+i+")?$",u="^("+o+")?"+i+o+i+o,a="^("+o+")?"+r;return function(n){var i,h,c,p,d,f,g;if(3>n.length)return n;if(c=n.substr(0,1),"y"==c&&(n=c.toUpperCase()+n.substr(1)),p=/^(.+?)(ss|i)es$/,d=/^(.+?)([^s])s$/,p.test(n)?n=n.replace(p,"$1$2"):d.test(n)&&(n=n.replace(d,"$1$2")),p=/^(.+?)eed$/,d=/^(.+?)(ed|ing)$/,p.test(n)){var m=p.exec(n);p=RegExp(s),p.test(m[1])&&(p=/.$/,n=n.replace(p,""))}else if(d.test(n)){var m=d.exec(n);i=m[1],d=RegExp(a),d.test(i)&&(n=i,d=/(at|bl|iz)$/,f=RegExp("([^aeiouylsz])\\1$"),g=RegExp("^"+o+r+"[^aeiouwxy]$"),d.test(n)?n+="e":f.test(n)?(p=/.$/,n=n.replace(p,"")):g.test(n)&&(n+="e"))}if(p=/^(.+?)y$/,p.test(n)){var m=p.exec(n);i=m[1],p=RegExp(a),p.test(i)&&(n=i+"i")}if(p=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,p.test(n)){var m=p.exec(n);i=m[1],h=m[2],p=RegExp(s),p.test(i)&&(n=i+e[h])}if(p=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,p.test(n)){var m=p.exec(n);i=m[1],h=m[2],p=RegExp(s),p.test(i)&&(n=i+t[h])}if(p=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,d=/^(.+?)(s|t)(ion)$/,p.test(n)){var m=p.exec(n);i=m[1],p=RegExp(u),p.test(i)&&(n=i)}else if(d.test(n)){var m=d.exec(n);i=m[1]+m[2],d=RegExp(u),d.test(i)&&(n=i)}if(p=/^(.+?)e$/,p.test(n)){var m=p.exec(n);i=m[1],p=RegExp(u),d=RegExp(l),f=RegExp("^"+o+r+"[^aeiouwxy]$"),(p.test(i)||d.test(i)&&!f.test(i))&&(n=i)}return p=/ll$/,d=RegExp(u),p.test(n)&&d.test(n)&&(p=/.$/,n=n.replace(p,"")),"y"==c&&(n=c.toLowerCase()+n.substr(1)),n}}(),lunr.Pipeline.registerFunction(lunr.stemmer,"stemmer"),lunr.stopWordFilter=function(e){return-1===lunr.stopWordFilter.stopWords.indexOf(e)?e:void 0},lunr.stopWordFilter.stopWords=new lunr.SortedSet,lunr.stopWordFilter.stopWords.length=119,lunr.stopWordFilter.stopWords.elements=["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"],lunr.Pipeline.registerFunction(lunr.stopWordFilter,"stopWordFilter"),lunr.TokenStore=function(){this.root={docs:{}},this.length=0},lunr.TokenStore.load=function(e){var t=new this;return t.root=e.root,t.length=e.length,t},lunr.TokenStore.prototype.add=function(e,t,n){var n=n||this.root,r=e[0],o=e.slice(1);return r in n||(n[r]={docs:{}}),0===o.length?(n[r].docs[t.ref]=t,this.length+=1,void 0):this.add(o,t,n[r])},lunr.TokenStore.prototype.has=function(e,t){var t=t||this.root,n=e[0],r=e.slice(1);return n in t?0===r.length?!0:this.has(r,t[n]):!1},lunr.TokenStore.prototype.getNode=function(e,t){var t=t||this.root,n=e[0],r=e.slice(1);return n in t?0===r.length?t[n]:this.getNode(r,t[n]):{}},lunr.TokenStore.prototype.get=function(e,t){return this.getNode(e,t).docs||{}},lunr.TokenStore.prototype.remove=function(e,t,n){var n=n||this.root,r=e[0],o=e.slice(1);if(r in n)return 0!==o.length?this.remove(o,t,n[r]):(delete n[r].docs[t],void 0)},lunr.TokenStore.prototype.expand=function(e,t){var n=this.getNode(e),r=n.docs||{},t=t||[];return Object.keys(r).length&&t.push(e),Object.keys(n).forEach(function(n){"docs"!==n&&t.concat(this.expand(e+n,t))},this),t},lunr.TokenStore.prototype.toJSON=function(){return{root:this.root,length:this.length}}; | ||
var lunr=function(t){var e=new lunr.Index;return e.pipeline.add(lunr.stopWordFilter,lunr.stemmer),t&&t.call(e,e),e};lunr.version="0.4.0","undefined"!=typeof module&&(module.exports=lunr),lunr.utils={},lunr.utils.warn=function(t){return function(e){t.console&&console.warn&&console.warn(e)}}(this),lunr.utils.zeroFillArray=function(){var t=[0];return function(e){for(;e>t.length;)t=t.concat(t);return t.slice(0,e)}}(),lunr.EventEmitter=function(){this.events={}},lunr.EventEmitter.prototype.addListener=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=t;if("function"!=typeof e)throw new TypeError("last argument must be a function");n.forEach(function(t){this.hasHandler(t)||(this.events[t]=[]),this.events[t].push(e)},this)},lunr.EventEmitter.prototype.removeListener=function(t,e){if(this.hasHandler(t)){var n=this.events[t].indexOf(e);this.events[t].splice(n,1),this.events[t].length||delete this.events[t]}},lunr.EventEmitter.prototype.emit=function(t){if(this.hasHandler(t)){var e=Array.prototype.slice.call(arguments,1);this.events[t].forEach(function(t){t.apply(void 0,e)})}},lunr.EventEmitter.prototype.hasHandler=function(t){return t in this.events},lunr.tokenizer=function(t){if(!t)return[];if(Array.isArray(t))return t;for(var t=t.replace(/^\s+/,""),e=t.length-1;e>=0;e--)if(/\S/.test(t.charAt(e))){t=t.substring(0,e+1);break}return t.split(/\s+/).map(function(t){return t.replace(/^\W+/,"").replace(/\W+$/,"").toLowerCase()})},lunr.Pipeline=function(){this._stack=[]},lunr.Pipeline.registeredFunctions={},lunr.Pipeline.registerFunction=function(t,e){e in this.registeredFunctions&&lunr.utils.warn("Overwriting existing registered function: "+e),t.label=e,lunr.Pipeline.registeredFunctions[t.label]=t},lunr.Pipeline.warnIfFunctionNotRegistered=function(t){var e=t.label&&t.label in this.registeredFunctions;e||lunr.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",t)},lunr.Pipeline.load=function(t){var e=new lunr.Pipeline;return t.forEach(function(t){var n=lunr.Pipeline.registeredFunctions[t];if(!n)throw Error("Cannot load un-registered function: "+t);e.add(n)}),e},lunr.Pipeline.prototype.add=function(){var t=Array.prototype.slice.call(arguments);t.forEach(function(t){lunr.Pipeline.warnIfFunctionNotRegistered(t),this._stack.push(t)},this)},lunr.Pipeline.prototype.after=function(t,e){lunr.Pipeline.warnIfFunctionNotRegistered(e);var n=this._stack.indexOf(t)+1;this._stack.splice(n,0,e)},lunr.Pipeline.prototype.before=function(t,e){lunr.Pipeline.warnIfFunctionNotRegistered(e);var n=this._stack.indexOf(t);this._stack.splice(n,0,e)},lunr.Pipeline.prototype.remove=function(t){var e=this._stack.indexOf(t);this._stack.splice(e,1)},lunr.Pipeline.prototype.run=function(t){for(var e=[],n=t.length,r=this._stack.length,i=0;n>i;i++){for(var o=t[i],s=0;r>s&&(o=this._stack[s](o,i,t),void 0!==o);s++);void 0!==o&&e.push(o)}return e},lunr.Pipeline.prototype.toJSON=function(){return this._stack.map(function(t){return lunr.Pipeline.warnIfFunctionNotRegistered(t),t.label})},lunr.Vector=function(t){this.elements=t},lunr.Vector.prototype.magnitude=function(){if(this._magnitude)return this._magnitude;for(var t,e=0,n=this.elements,r=n.length,i=0;r>i;i++)t=n[i],e+=t*t;return this._magnitude=Math.sqrt(e)},lunr.Vector.prototype.dot=function(t){for(var e=this.elements,n=t.elements,r=e.length,i=0,o=0;r>o;o++)i+=e[o]*n[o];return i},lunr.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},lunr.Vector.prototype.toArray=function(){return this.elements},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},lunr.SortedSet.prototype.add=function(){Array.prototype.slice.call(arguments).forEach(function(t){~this.indexOf(t)||this.elements.splice(this.locationFor(t),0,t)},this),this.length=this.elements.length},lunr.SortedSet.prototype.toArray=function(){return this.elements.slice()},lunr.SortedSet.prototype.map=function(t,e){return this.elements.map(t,e)},lunr.SortedSet.prototype.forEach=function(t,e){return this.elements.forEach(t,e)},lunr.SortedSet.prototype.indexOf=function(t,e,n){var e=e||0,n=n||this.elements.length,r=n-e,i=e+Math.floor(r/2),o=this.elements[i];return 1>=r?o===t?i:-1:t>o?this.indexOf(t,i,n):o>t?this.indexOf(t,e,i):o===t?i:void 0},lunr.SortedSet.prototype.locationFor=function(t,e,n){var e=e||0,n=n||this.elements.length,r=n-e,i=e+Math.floor(r/2),o=this.elements[i];if(1>=r){if(o>t)return i;if(t>o)return i+1}return t>o?this.locationFor(t,i,n):o>t?this.locationFor(t,e,i):void 0},lunr.SortedSet.prototype.intersect=function(t){for(var e=new lunr.SortedSet,n=0,r=0,i=this.length,o=t.length,s=this.elements,l=t.elements;;){if(n>i-1||r>o-1)break;s[n]!==l[r]?s[n]<l[r]?n++:s[n]>l[r]&&r++:(e.add(s[n]),n++,r++)}return e},lunr.SortedSet.prototype.clone=function(){var t=new lunr.SortedSet;return t.elements=this.toArray(),t.length=t.elements.length,t},lunr.SortedSet.prototype.union=function(t){var e,n,r;return this.length>=t.length?(e=this,n=t):(e=t,n=this),r=e.clone(),r.add.apply(r,n.toArray()),r},lunr.SortedSet.prototype.toJSON=function(){return this.toArray()},lunr.Index=function(){this._fields=[],this._ref="id",this.pipeline=new lunr.Pipeline,this.documentStore=new lunr.Store,this.tokenStore=new lunr.TokenStore,this.corpusTokens=new lunr.SortedSet,this.eventEmitter=new lunr.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},lunr.Index.prototype.on=function(){var t=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,t)},lunr.Index.prototype.off=function(t,e){return this.eventEmitter.removeListener(t,e)},lunr.Index.load=function(t){t.version!==lunr.version&&lunr.utils.warn("version mismatch: current "+lunr.version+" importing "+t.version);var e=new this;return e._fields=t.fields,e._ref=t.ref,e.documentStore=lunr.Store.load(t.documentStore),e.tokenStore=lunr.TokenStore.load(t.tokenStore),e.corpusTokens=lunr.SortedSet.load(t.corpusTokens),e.pipeline=lunr.Pipeline.load(t.pipeline),e},lunr.Index.prototype.field=function(t,e){var e=e||{},n={name:t,boost:e.boost||1};return this._fields.push(n),this},lunr.Index.prototype.ref=function(t){return this._ref=t,this},lunr.Index.prototype.add=function(t,e){var n={},r=new lunr.SortedSet,i=t[this._ref],e=void 0===e?!0:e;this._fields.forEach(function(e){var i=this.pipeline.run(lunr.tokenizer(t[e.name]));n[e.name]=i,lunr.SortedSet.prototype.add.apply(r,i)},this),this.documentStore.set(i,r),lunr.SortedSet.prototype.add.apply(this.corpusTokens,r.toArray());for(var o=0;r.length>o;o++){var s=r.elements[o],l=this._fields.reduce(function(t,e){var r=n[e.name].length;if(!r)return t;var i=n[e.name].filter(function(t){return t===s}).length;return t+i/r*e.boost},0);this.tokenStore.add(s,{ref:i,tf:l})}e&&this.eventEmitter.emit("add",t,this)},lunr.Index.prototype.remove=function(t,e){var n=t[this._ref],e=void 0===e?!0:e;if(this.documentStore.has(n)){var r=this.documentStore.get(n);this.documentStore.remove(n),r.forEach(function(t){this.tokenStore.remove(t,n)},this),e&&this.eventEmitter.emit("remove",t,this)}},lunr.Index.prototype.update=function(t,e){var e=void 0===e?!0:e;this.remove(t,!1),this.add(t,!1),e&&this.eventEmitter.emit("update",t,this)},lunr.Index.prototype.idf=function(t){if(this._idfCache[t])return this._idfCache[t];var e=this.tokenStore.count(t),n=1;return e>0&&(n=1+Math.log(this.tokenStore.length/e)),this._idfCache[t]=n},lunr.Index.prototype.search=function(t){var e=this.pipeline.run(lunr.tokenizer(t)),n=lunr.utils.zeroFillArray(this.corpusTokens.length),r=[],i=this._fields.reduce(function(t,e){return t+e.boost},0),o=e.some(function(t){return this.tokenStore.has(t)},this);if(!o)return[];e.forEach(function(t,e,o){var s=1/o.length*this._fields.length*i,l=this,u=this.tokenStore.expand(t).reduce(function(e,r){var i=l.corpusTokens.indexOf(r),o=l.idf(r),u=1,a=new lunr.SortedSet;if(r!==t){var h=Math.max(3,r.length-t.length);u=1/Math.log(h)}return i>-1&&(n[i]=s*o*u),Object.keys(l.tokenStore.get(r)).forEach(function(t){a.add(t)}),e.union(a)},new lunr.SortedSet);r.push(u)},this);var s=r.reduce(function(t,e){return t.intersect(e)}),l=new lunr.Vector(n);return s.map(function(t){return{ref:t,score:l.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},lunr.Index.prototype.documentVector=function(t){for(var e=this.documentStore.get(t),n=e.length,r=lunr.utils.zeroFillArray(this.corpusTokens.length),i=0;n>i;i++){var o=e.elements[i],s=this.tokenStore.get(o)[t].tf,l=this.idf(o);r[this.corpusTokens.indexOf(o)]=s*l}return new lunr.Vector(r)},lunr.Index.prototype.toJSON=function(){return{version:lunr.version,fields:this._fields,ref:this._ref,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},lunr.Store=function(){this.store={},this.length=0},lunr.Store.load=function(t){var e=new this;return e.length=t.length,e.store=Object.keys(t.store).reduce(function(e,n){return e[n]=lunr.SortedSet.load(t.store[n]),e},{}),e},lunr.Store.prototype.set=function(t,e){this.store[t]=e,this.length=Object.keys(this.store).length},lunr.Store.prototype.get=function(t){return this.store[t]},lunr.Store.prototype.has=function(t){return t in this.store},lunr.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},lunr.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},lunr.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",r="[aeiouy]",i=n+"[^aeiouy]*",o=r+"[aeiou]*",s="^("+i+")?"+o+i,l="^("+i+")?"+o+i+"("+o+")?$",u="^("+i+")?"+o+i+o+i,a="^("+i+")?"+r;return function(n){var o,h,c,p,f,d,v;if(3>n.length)return n;if(c=n.substr(0,1),"y"==c&&(n=c.toUpperCase()+n.substr(1)),p=/^(.+?)(ss|i)es$/,f=/^(.+?)([^s])s$/,p.test(n)?n=n.replace(p,"$1$2"):f.test(n)&&(n=n.replace(f,"$1$2")),p=/^(.+?)eed$/,f=/^(.+?)(ed|ing)$/,p.test(n)){var m=p.exec(n);p=RegExp(s),p.test(m[1])&&(p=/.$/,n=n.replace(p,""))}else if(f.test(n)){var m=f.exec(n);o=m[1],f=RegExp(a),f.test(o)&&(n=o,f=/(at|bl|iz)$/,d=RegExp("([^aeiouylsz])\\1$"),v=RegExp("^"+i+r+"[^aeiouwxy]$"),f.test(n)?n+="e":d.test(n)?(p=/.$/,n=n.replace(p,"")):v.test(n)&&(n+="e"))}if(p=/^(.+?)y$/,p.test(n)){var m=p.exec(n);o=m[1],p=RegExp(a),p.test(o)&&(n=o+"i")}if(p=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,p.test(n)){var m=p.exec(n);o=m[1],h=m[2],p=RegExp(s),p.test(o)&&(n=o+t[h])}if(p=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,p.test(n)){var m=p.exec(n);o=m[1],h=m[2],p=RegExp(s),p.test(o)&&(n=o+e[h])}if(p=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,f=/^(.+?)(s|t)(ion)$/,p.test(n)){var m=p.exec(n);o=m[1],p=RegExp(u),p.test(o)&&(n=o)}else if(f.test(n)){var m=f.exec(n);o=m[1]+m[2],f=RegExp(u),f.test(o)&&(n=o)}if(p=/^(.+?)e$/,p.test(n)){var m=p.exec(n);o=m[1],p=RegExp(u),f=RegExp(l),d=RegExp("^"+i+r+"[^aeiouwxy]$"),(p.test(o)||f.test(o)&&!d.test(o))&&(n=o)}return p=/ll$/,f=RegExp(u),p.test(n)&&f.test(n)&&(p=/.$/,n=n.replace(p,"")),"y"==c&&(n=c.toLowerCase()+n.substr(1)),n}}(),lunr.Pipeline.registerFunction(lunr.stemmer,"stemmer"),lunr.stopWordFilter=function(t){return-1===lunr.stopWordFilter.stopWords.indexOf(t)?t:void 0},lunr.stopWordFilter.stopWords=new lunr.SortedSet,lunr.stopWordFilter.stopWords.length=119,lunr.stopWordFilter.stopWords.elements=["","a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"],lunr.Pipeline.registerFunction(lunr.stopWordFilter,"stopWordFilter"),lunr.TokenStore=function(){this.root={docs:{}},this.length=0},lunr.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},lunr.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,r=t[0],i=t.slice(1);return r in n||(n[r]={docs:{}}),0===i.length?(n[r].docs[e.ref]=e,this.length+=1,void 0):this.add(i,e,n[r])},lunr.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;t.length>n;n++){if(!e[t[n]])return!1;e=e[t[n]]}return!0},lunr.TokenStore.prototype.getNode=function(t){if(!t)return{};for(var e=this.root,n=0;t.length>n;n++){if(!e[t[n]])return{};e=e[t[n]]}return e},lunr.TokenStore.prototype.get=function(t,e){return this.getNode(t,e).docs||{}},lunr.TokenStore.prototype.count=function(t,e){return Object.keys(this.get(t,e)).length},lunr.TokenStore.prototype.remove=function(t,e){if(t){for(var n=this.root,r=0;t.length>r;r++){if(!(t[r]in n))return;n=n[t[r]]}delete n.docs[e]}},lunr.TokenStore.prototype.expand=function(t,e){var n=this.getNode(t),r=n.docs||{},e=e||[];return Object.keys(r).length&&e.push(t),Object.keys(n).forEach(function(n){"docs"!==n&&e.concat(this.expand(t+n,e))},this),e},lunr.TokenStore.prototype.toJSON=function(){return{root:this.root,length:this.length}}; |
{ | ||
"name": "lunr", | ||
"description": "Simple full-text search in your browser.", | ||
"version": "0.3.3", | ||
"version": "0.4.0", | ||
"author": "Oliver Nightingale", | ||
@@ -6,0 +6,0 @@ "keywords": ["search"], |
@@ -1,27 +0,28 @@ | ||
var suite = new Benchmark.Suite, | ||
testDoc = { | ||
(function () { | ||
var setup = function () { | ||
var testDoc = { | ||
id: 1, | ||
title: 'Adding story from last story in the sprint', | ||
body: 'So that I am not confused where the story is going to end up As a user I want the the add a story button from the last story in the sprint to create a story at the top of the backlog and not extend the sprint temporarily the add story button inserts a story at the top of the backlog. "add a new story here" prompts are not shown for stories that are currently in a sprint' | ||
body: 'So that I am not confused where the story is going to end up As a user I want the the add a story button from the last story in the sprint to create a story at the top of the backlog and not extend the sprint temporarily the add story button inserts a story at the top of the backlog. "add a new story here" prompts are not shown for stories that are currently in a sprint', | ||
tags: 'foo bar' | ||
} | ||
suite.add('index#add', function () { | ||
var idx = lunr(function () { | ||
this.field('title', 10) | ||
this.field('body') | ||
}) | ||
questionsIdx.version = lunr.version | ||
idx.add(testDoc) | ||
}) | ||
var idx = lunr.Index.load(questionsIdx) | ||
} | ||
suite.on('cycle', function (e) { | ||
console.log(e.target.name) | ||
}) | ||
bench('index#add', function () { | ||
idx.add(testDoc) | ||
}, { setup: setup }) | ||
suite.on('complete', function (e) { | ||
suite.forEach(function (s) { | ||
console.log(s.name, s.count) | ||
}) | ||
}) | ||
bench('index#search uncommon word', function () { | ||
idx.search('checkbox') | ||
}, { setup: setup }) | ||
suite.run({async: true}) | ||
bench('index#search common word', function () { | ||
idx.search('javascript') | ||
}, { setup: setup }) | ||
})() | ||
@@ -1,30 +0,38 @@ | ||
var suite = new Benchmark.Suite, | ||
elements = [] | ||
(function () { | ||
for (var i = 0; i < 1000; i++) { | ||
elements[i] = Math.random() * 100 | ||
}; | ||
var setup = function () { | ||
var elements1 = lunr.Vector.oliver(10000), | ||
elements2 = lunr.Vector.oliver(10000), | ||
index | ||
suite.add('vector#magnitude', function () { | ||
var vector = new lunr.Vector (elements) | ||
vector.magnitude() | ||
}) | ||
for (var i = 0; i < 1000; i++) { | ||
index = Math.floor(i + Math.random() * 100) | ||
elements1[i] = Math.random() * 100 | ||
} | ||
suite.add('vector#dot', function () { | ||
var v1 = new lunr.Vector(elements), | ||
v2 = new lunr.Vector(elements) | ||
for (var i = 0; i < 1000; i++) { | ||
index = Math.floor(i + Math.random() * 100) | ||
elements2[i] = Math.random() * 100 | ||
} | ||
} | ||
v1.dot(v2) | ||
}) | ||
bench('vector#magnitude', function () { | ||
var vector = new lunr.Vector (elements1) | ||
vector.magnitude | ||
}, { setup: setup }) | ||
suite.on('cycle', function (e) { | ||
console.log(e.target.name) | ||
}) | ||
bench('vector#dot', function () { | ||
var v1 = new lunr.Vector(elements1), | ||
v2 = new lunr.Vector(elements2) | ||
suite.on('complete', function (e) { | ||
suite.forEach(function (s) { | ||
console.log(s.name, s.count) | ||
}) | ||
}) | ||
v1.dot(v2) | ||
}, { setup: setup }) | ||
suite.run({async: true}) | ||
bench('vector#similarity', function () { | ||
var v1 = new lunr.Vector(elements1), | ||
v2 = new lunr.Vector(elements2) | ||
v1.similarity(v2) | ||
}, { setup: setup }) | ||
})() | ||
@@ -51,2 +51,39 @@ module('lunr.Index') | ||
test('triggering add events', function () { | ||
var idx = new lunr.Index, | ||
doc = {id: 1, body: 'this is a test'}, | ||
callbackCalled = false, | ||
callbackArgs = [] | ||
idx.on('add', function (doc, index) { | ||
callbackCalled = true | ||
callbackArgs = Array.prototype.slice.call(arguments) | ||
}) | ||
idx.field('body') | ||
idx.add(doc) | ||
ok(callbackCalled) | ||
equal(callbackArgs.length, 2) | ||
deepEqual(callbackArgs[0], doc) | ||
deepEqual(callbackArgs[1], idx) | ||
}) | ||
test('silencing add events', function () { | ||
var idx = new lunr.Index, | ||
doc = {id: 1, body: 'this is a test'}, | ||
callbackCalled = false, | ||
callbackArgs = [] | ||
idx.on('add', function (doc, index) { | ||
callbackCalled = true | ||
callbackArgs = Array.prototype.slice.call(arguments) | ||
}) | ||
idx.field('body') | ||
idx.add(doc, false) | ||
ok(!callbackCalled) | ||
}) | ||
test('removing a document from the index', function () { | ||
@@ -66,7 +103,51 @@ var idx = new lunr.Index, | ||
test('triggering remove events', function () { | ||
var idx = new lunr.Index, | ||
doc = {id: 1, body: 'this is a test'}, | ||
callbackCalled = false, | ||
callbackArgs = [] | ||
idx.on('remove', function (doc, index) { | ||
callbackCalled = true | ||
callbackArgs = Array.prototype.slice.call(arguments) | ||
}) | ||
idx.field('body') | ||
idx.add(doc) | ||
idx.remove(doc) | ||
ok(callbackCalled) | ||
equal(callbackArgs.length, 2) | ||
deepEqual(callbackArgs[0], doc) | ||
deepEqual(callbackArgs[1], idx) | ||
}) | ||
test('silencing remove events', function () { | ||
var idx = new lunr.Index, | ||
doc = {id: 1, body: 'this is a test'}, | ||
callbackCalled = false, | ||
callbackArgs = [] | ||
idx.on('remove', function (doc, index) { | ||
callbackCalled = true | ||
callbackArgs = Array.prototype.slice.call(arguments) | ||
}) | ||
idx.field('body') | ||
idx.add(doc) | ||
idx.remove(doc, false) | ||
ok(!callbackCalled) | ||
}) | ||
test('removing a non-existent document from the index', function () { | ||
var idx = new lunr.Index, | ||
doc = {id: 1, body: 'this is a test'}, | ||
doc2 = {id: 2, body: 'i dont exist'} | ||
doc2 = {id: 2, body: 'i dont exist'}, | ||
callbackCalled = false | ||
idx.on('remove', function (doc, index) { | ||
callbackCalled = true | ||
}) | ||
idx.field('body') | ||
@@ -80,2 +161,4 @@ equal(idx.documentStore.length, 0) | ||
equal(idx.documentStore.length, 1) | ||
ok(!callbackCalled) | ||
}) | ||
@@ -99,2 +182,61 @@ | ||
test('emitting update events', function () { | ||
var idx = new lunr.Index, | ||
doc = {id: 1, body: 'foo'} | ||
addCallbackCalled = false, | ||
removeCallbackCalled = false, | ||
updateCallbackCalled = false, | ||
callbackArgs = [] | ||
idx.field('body') | ||
idx.add(doc) | ||
equal(idx.documentStore.length, 1) | ||
ok(idx.tokenStore.has('foo')) | ||
idx.on('update', function (doc, index) { | ||
updateCallbackCalled = true | ||
callbackArgs = Array.prototype.slice.call(arguments) | ||
}) | ||
idx.on('add', function () { | ||
addCallbackCalled = true | ||
}) | ||
idx.on('remove', function () { | ||
removeCallbackCalled = true | ||
}) | ||
doc.body = 'bar' | ||
idx.update(doc) | ||
ok(updateCallbackCalled) | ||
equal(callbackArgs.length, 2) | ||
deepEqual(callbackArgs[0], doc) | ||
deepEqual(callbackArgs[1], idx) | ||
ok(!addCallbackCalled) | ||
ok(!removeCallbackCalled) | ||
}) | ||
test('silencing update events', function () { | ||
var idx = new lunr.Index, | ||
doc = {id: 1, body: 'foo'} | ||
callbackCalled = false | ||
idx.field('body') | ||
idx.add(doc) | ||
equal(idx.documentStore.length, 1) | ||
ok(idx.tokenStore.has('foo')) | ||
idx.on('update', function (doc, index) { | ||
callbackCalled = true | ||
}) | ||
doc.body = 'bar' | ||
idx.update(doc, false) | ||
ok(!callbackCalled) | ||
}) | ||
test('serialising', function () { | ||
@@ -101,0 +243,0 @@ var idx = new lunr.Index, |
@@ -24,7 +24,7 @@ module('search', { | ||
id: 'd', | ||
title: '', | ||
title: 'title', | ||
body: 'handsome', | ||
},{ | ||
id: 'e', | ||
title: '', | ||
title: 'title', | ||
body: 'hand', | ||
@@ -31,0 +31,0 @@ }]).forEach(function (doc) { idx.add(doc) }) |
@@ -56,2 +56,4 @@ module('lunr.TokenStore') | ||
}) | ||
deepEqual(store.get(''), {}) | ||
}) | ||
@@ -65,2 +67,17 @@ | ||
test('counting items in the store', function () { | ||
var store = new lunr.TokenStore, | ||
doc1 = { ref: 123, tf: 1 }, | ||
doc2 = { ref: 456, tf: 1 }, | ||
doc3 = { ref: 789, tf: 1 } | ||
store.add('foo', doc1) | ||
store.add('foo', doc2) | ||
store.add('bar', doc3) | ||
equal(store.count('foo'), 2) | ||
equal(store.count('bar'), 1) | ||
equal(store.count('baz'), 0) | ||
}) | ||
test('removing a document from the token store', function () { | ||
@@ -67,0 +84,0 @@ var store = new lunr.TokenStore, |
@@ -1,16 +0,10 @@ | ||
module('utils') | ||
module('lunr.utils') | ||
test('wrapping in an array', function() { | ||
same(lunr.utils.arrayWrap(1), [1]) | ||
same(lunr.utils.arrayWrap('a'), ['a']) | ||
same(lunr.utils.arrayWrap({}), [{}]) | ||
same(lunr.utils.arrayWrap([]), []) | ||
same(lunr.utils.arrayWrap([1]), [1]) | ||
same(lunr.utils.arrayWrap(undefined), []) | ||
same(lunr.utils.arrayWrap(null), []) | ||
test('zeroFillArray', function() { | ||
var arr = lunr.utils.zeroFillArray(10) | ||
equal(arr.length, 10) | ||
ok(arr.every(function (el) { return el === 0 })) | ||
ok(arr !== lunr.utils.zeroFillArray(10)) | ||
}) | ||
test('flattening an array', function () { | ||
same(lunr.utils.flatten([1,2,3]), [1,2,3]) | ||
same(lunr.utils.flatten([1, [2, [3]]]), [1,2,3]) | ||
}) |
@@ -25,6 +25,1 @@ module("lunr.Vector") | ||
test('zero filling vectors created with sparse arrays', function () { | ||
var v1 = new lunr.Vector (new Array (10)) | ||
equal(v1.elements.length, 10) | ||
ok(v1.elements.every(function (el) { return el !== undefined })) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
3309307
79
31691