elasticlunr
Version:
Lightweight full-text search engine in Javascript for browser search and offline search.
256 lines (225 loc) • 7.42 kB
JavaScript
/*!
* elasticlunr.Pipeline
* Copyright (C) @YEAR Oliver Nightingale
* Copyright (C) @YEAR Wei Song
*/
/**
* elasticlunr.Pipelines maintain an ordered list of functions to be applied to
* both documents tokens and query tokens.
*
* An instance of elasticlunr.Index will contain a pipeline
* with a trimmer, a stop word filter, an English stemmer. Extra
* functions can be added before or after either of these functions or these
* default functions can be removed.
*
* When run the pipeline, it will call each function in turn.
*
* The output of the 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 elasticlunr.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
*/
elasticlunr.Pipeline = function () {
this._queue = [];
};
elasticlunr.Pipeline.registeredFunctions = {};
/**
* Register a function in 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 register.
* @param {String} label The label to register this function with
* @memberOf Pipeline
*/
elasticlunr.Pipeline.registerFunction = function (fn, label) {
if (label in elasticlunr.Pipeline.registeredFunctions) {
elasticlunr.utils.warn('Overwriting existing registered function: ' + label);
}
fn.label = label;
elasticlunr.Pipeline.registeredFunctions[label] = fn;
};
/**
* Get a registered function in the pipeline.
*
* @param {String} label The label of registered function.
* @return {Function}
* @memberOf Pipeline
*/
elasticlunr.Pipeline.getRegisteredFunction = function (label) {
if ((label in elasticlunr.Pipeline.registeredFunctions) !== true) {
return null;
}
return elasticlunr.Pipeline.registeredFunctions[label];
};
/**
* Warns if the function is not registered as a Pipeline function.
*
* @param {Function} fn The function to check for.
* @private
* @memberOf Pipeline
*/
elasticlunr.Pipeline.warnIfFunctionNotRegistered = function (fn) {
var isRegistered = fn.label && (fn.label in this.registeredFunctions);
if (!isRegistered) {
elasticlunr.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 elasticlunr.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.
* @return {elasticlunr.Pipeline}
* @memberOf Pipeline
*/
elasticlunr.Pipeline.load = function (serialised) {
var pipeline = new elasticlunr.Pipeline;
serialised.forEach(function (fnName) {
var fn = elasticlunr.Pipeline.getRegisteredFunction(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
*/
elasticlunr.Pipeline.prototype.add = function () {
var fns = Array.prototype.slice.call(arguments);
fns.forEach(function (fn) {
elasticlunr.Pipeline.warnIfFunctionNotRegistered(fn);
this._queue.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.
* If existingFn is not found, throw an Exception.
*
* @param {Function} existingFn A function that already exists in the pipeline.
* @param {Function} newFn The new function to add to the pipeline.
* @memberOf Pipeline
*/
elasticlunr.Pipeline.prototype.after = function (existingFn, newFn) {
elasticlunr.Pipeline.warnIfFunctionNotRegistered(newFn);
var pos = this._queue.indexOf(existingFn);
if (pos === -1) {
throw new Error('Cannot find existingFn');
}
this._queue.splice(pos + 1, 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.
* If existingFn is not found, throw an Exception.
*
* @param {Function} existingFn A function that already exists in the pipeline.
* @param {Function} newFn The new function to add to the pipeline.
* @memberOf Pipeline
*/
elasticlunr.Pipeline.prototype.before = function (existingFn, newFn) {
elasticlunr.Pipeline.warnIfFunctionNotRegistered(newFn);
var pos = this._queue.indexOf(existingFn);
if (pos === -1) {
throw new Error('Cannot find existingFn');
}
this._queue.splice(pos, 0, newFn);
};
/**
* Removes a function from the pipeline.
*
* @param {Function} fn The function to remove from the pipeline.
* @memberOf Pipeline
*/
elasticlunr.Pipeline.prototype.remove = function (fn) {
var pos = this._queue.indexOf(fn);
if (pos === -1) {
return;
}
this._queue.splice(pos, 1);
};
/**
* Runs the current list of functions that registered in the pipeline against the
* input tokens.
*
* @param {Array} tokens The tokens to run through the pipeline.
* @return {Array}
* @memberOf Pipeline
*/
elasticlunr.Pipeline.prototype.run = function (tokens) {
var out = [],
tokenLength = tokens.length,
pipelineLength = this._queue.length;
for (var i = 0; i < tokenLength; i++) {
var token = tokens[i];
for (var j = 0; j < pipelineLength; j++) {
token = this._queue[j](token, i, tokens);
if (token === void 0 || token === null) break;
};
if (token !== void 0 && token !== null) out.push(token);
};
return out;
};
/**
* Resets the pipeline by removing any existing processors.
*
* @memberOf Pipeline
*/
elasticlunr.Pipeline.prototype.reset = function () {
this._queue = [];
};
/**
* Get the pipeline if user want to check the pipeline.
*
* @memberOf Pipeline
*/
elasticlunr.Pipeline.prototype.get = function () {
return this._queue;
};
/**
* Returns a representation of the pipeline ready for serialisation.
* Only serialize pipeline function's name. Not storing function, so when
* loading the archived JSON index file, corresponding pipeline function is
* added by registered function of elasticlunr.Pipeline.registeredFunctions
*
* Logs a warning if the function has not been registered.
*
* @return {Array}
* @memberOf Pipeline
*/
elasticlunr.Pipeline.prototype.toJSON = function () {
return this._queue.map(function (fn) {
elasticlunr.Pipeline.warnIfFunctionNotRegistered(fn);
return fn.label;
});
};