231 lines
6.3 KiB
JavaScript
231 lines
6.3 KiB
JavaScript
|
/*!
|
||
|
* lunr.Pipeline
|
||
|
* Copyright (C) @YEAR Oliver Nightingale
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* lunr.Pipelines maintain an ordered list of functions to be applied to all
|
||
|
* tokens in documents entering the search index and queries being ran against
|
||
|
* the index.
|
||
|
*
|
||
|
* An instance of lunr.Index created with the lunr shortcut will contain a
|
||
|
* pipeline with a stop word filter and an English language stemmer. Extra
|
||
|
* functions can be added before or after either of these functions or these
|
||
|
* default functions can be removed.
|
||
|
*
|
||
|
* When run the pipeline will call each function in turn, passing a token, the
|
||
|
* index of that token in the original list of all tokens and finally a list of
|
||
|
* all the original tokens.
|
||
|
*
|
||
|
* The output of functions in the pipeline will be passed to the next function
|
||
|
* in the pipeline. To exclude a token from entering the index the function
|
||
|
* should return undefined, the rest of the pipeline will not be called with
|
||
|
* this token.
|
||
|
*
|
||
|
* For serialisation of pipelines to work, all functions used in an instance of
|
||
|
* a pipeline should be registered with lunr.Pipeline. Registered functions can
|
||
|
* then be loaded. If trying to load a serialised pipeline that uses functions
|
||
|
* that are not registered an error will be thrown.
|
||
|
*
|
||
|
* If not planning on serialising the pipeline then registering pipeline functions
|
||
|
* is not necessary.
|
||
|
*
|
||
|
* @constructor
|
||
|
*/
|
||
|
lunr.Pipeline = function () {
|
||
|
this._stack = []
|
||
|
}
|
||
|
|
||
|
lunr.Pipeline.registeredFunctions = {}
|
||
|
|
||
|
/**
|
||
|
* Register a function with the pipeline.
|
||
|
*
|
||
|
* Functions that are used in the pipeline should be registered if the pipeline
|
||
|
* needs to be serialised, or a serialised pipeline needs to be loaded.
|
||
|
*
|
||
|
* Registering a function does not add it to a pipeline, functions must still be
|
||
|
* added to instances of the pipeline for them to be used when running a pipeline.
|
||
|
*
|
||
|
* @param {Function} fn The function to check for.
|
||
|
* @param {String} label The label to register this function with
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.registerFunction = function (fn, label) {
|
||
|
if (label in this.registeredFunctions) {
|
||
|
lunr.utils.warn('Overwriting existing registered function: ' + label)
|
||
|
}
|
||
|
|
||
|
fn.label = label
|
||
|
lunr.Pipeline.registeredFunctions[fn.label] = fn
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Warns if the function is not registered as a Pipeline function.
|
||
|
*
|
||
|
* @param {Function} fn The function to check for.
|
||
|
* @private
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.warnIfFunctionNotRegistered = function (fn) {
|
||
|
var isRegistered = fn.label && (fn.label in this.registeredFunctions)
|
||
|
|
||
|
if (!isRegistered) {
|
||
|
lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\n', fn)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Loads a previously serialised pipeline.
|
||
|
*
|
||
|
* All functions to be loaded must already be registered with lunr.Pipeline.
|
||
|
* If any function from the serialised data has not been registered then an
|
||
|
* error will be thrown.
|
||
|
*
|
||
|
* @param {Object} serialised The serialised pipeline to load.
|
||
|
* @returns {lunr.Pipeline}
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.load = function (serialised) {
|
||
|
var pipeline = new lunr.Pipeline
|
||
|
|
||
|
serialised.forEach(function (fnName) {
|
||
|
var fn = lunr.Pipeline.registeredFunctions[fnName]
|
||
|
|
||
|
if (fn) {
|
||
|
pipeline.add(fn)
|
||
|
} else {
|
||
|
throw new Error('Cannot load un-registered function: ' + fnName)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
return pipeline
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds new functions to the end of the pipeline.
|
||
|
*
|
||
|
* Logs a warning if the function has not been registered.
|
||
|
*
|
||
|
* @param {Function} functions Any number of functions to add to the pipeline.
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.prototype.add = function () {
|
||
|
var fns = Array.prototype.slice.call(arguments)
|
||
|
|
||
|
fns.forEach(function (fn) {
|
||
|
lunr.Pipeline.warnIfFunctionNotRegistered(fn)
|
||
|
this._stack.push(fn)
|
||
|
}, this)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds a single function after a function that already exists in the
|
||
|
* pipeline.
|
||
|
*
|
||
|
* Logs a warning if the function has not been registered.
|
||
|
*
|
||
|
* @param {Function} existingFn A function that already exists in the pipeline.
|
||
|
* @param {Function} newFn The new function to add to the pipeline.
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.prototype.after = function (existingFn, newFn) {
|
||
|
lunr.Pipeline.warnIfFunctionNotRegistered(newFn)
|
||
|
|
||
|
var pos = this._stack.indexOf(existingFn)
|
||
|
if (pos == -1) {
|
||
|
throw new Error('Cannot find existingFn')
|
||
|
}
|
||
|
|
||
|
pos = pos + 1
|
||
|
this._stack.splice(pos, 0, newFn)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds a single function before a function that already exists in the
|
||
|
* pipeline.
|
||
|
*
|
||
|
* Logs a warning if the function has not been registered.
|
||
|
*
|
||
|
* @param {Function} existingFn A function that already exists in the pipeline.
|
||
|
* @param {Function} newFn The new function to add to the pipeline.
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.prototype.before = function (existingFn, newFn) {
|
||
|
lunr.Pipeline.warnIfFunctionNotRegistered(newFn)
|
||
|
|
||
|
var pos = this._stack.indexOf(existingFn)
|
||
|
if (pos == -1) {
|
||
|
throw new Error('Cannot find existingFn')
|
||
|
}
|
||
|
|
||
|
this._stack.splice(pos, 0, newFn)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Removes a function from the pipeline.
|
||
|
*
|
||
|
* @param {Function} fn The function to remove from the pipeline.
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.prototype.remove = function (fn) {
|
||
|
var pos = this._stack.indexOf(fn)
|
||
|
if (pos == -1) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
this._stack.splice(pos, 1)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Runs the current list of functions that make up the pipeline against the
|
||
|
* passed tokens.
|
||
|
*
|
||
|
* @param {Array} tokens The tokens to run through the pipeline.
|
||
|
* @returns {Array}
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.prototype.run = function (tokens) {
|
||
|
var out = [],
|
||
|
tokenLength = tokens.length,
|
||
|
stackLength = this._stack.length
|
||
|
|
||
|
for (var i = 0; i < tokenLength; i++) {
|
||
|
var token = tokens[i]
|
||
|
|
||
|
for (var j = 0; j < stackLength; j++) {
|
||
|
token = this._stack[j](token, i, tokens)
|
||
|
if (token === void 0 || token === '') break
|
||
|
};
|
||
|
|
||
|
if (token !== void 0 && token !== '') out.push(token)
|
||
|
};
|
||
|
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Resets the pipeline by removing any existing processors.
|
||
|
*
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.prototype.reset = function () {
|
||
|
this._stack = []
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a representation of the pipeline ready for serialisation.
|
||
|
*
|
||
|
* Logs a warning if the function has not been registered.
|
||
|
*
|
||
|
* @returns {Array}
|
||
|
* @memberOf Pipeline
|
||
|
*/
|
||
|
lunr.Pipeline.prototype.toJSON = function () {
|
||
|
return this._stack.map(function (fn) {
|
||
|
lunr.Pipeline.warnIfFunctionNotRegistered(fn)
|
||
|
|
||
|
return fn.label
|
||
|
})
|
||
|
}
|