UNPKG

elasticlunr

Version:

Lightweight full-text search engine in Javascript for browser search and offline search.

256 lines (225 loc) 7.42 kB
/*! * 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; }); };