UNPKG

lunr-elastic-search

Version:

Uses Lunr.js to index and search the knowledge base.

505 lines (447 loc) 18.3 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Source: lunr.js | lunr-elastic-search</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css"> <link type="text/css" rel="stylesheet" href="styles/prettify-jsdoc.css"> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/tui-doc.css"> </head> <body> <nav class="lnb" id="lnb"> <div class="logo" style=""> <img src="img/toast-ui.png" width="100%" height="100%"> </div> <div class="title"> <h1><a href="index.html" class="link">lunr-elastic-search</a></h1> </div> <div class="search-container" id="search-container"> <input type="text" placeholder="Search"> <ul></ul> </div> <div class="lnb-api hidden"><h3>Classes</h3><ul><li><a href="LunrSearch.html">LunrSearch</a><button type="button" class="hidden toggle-subnav btn btn-link"> <span class="glyphicon glyphicon-plus"></span></button><div class="hidden" id="LunrSearch_sub"><div class="member-type">Members</div><ul class="inner"><li><a href="LunrSearch.html#.VERSION">VERSION</a></li><li><a href="LunrSearch.html#builder">builder</a></li><li><a href="LunrSearch.html#docs">docs</a></li><li><a href="LunrSearch.html#domain">domain</a></li><li><a href="LunrSearch.html#editDistance">editDistance</a></li><li><a href="LunrSearch.html#index">index</a></li><li><a href="LunrSearch.html#pass">pass</a></li><li><a href="LunrSearch.html#plugins">plugins</a></li><li><a href="LunrSearch.html#user">user</a></li></ul><div class="member-type">Methods</div><ul class="inner"><li><a href="LunrSearch.html#.buildIndex">buildIndex</a></li><li><a href="LunrSearch.html#.exportIndex">exportIndex</a></li><li><a href="LunrSearch.html#.fetch">fetch</a></li><li><a href="LunrSearch.html#.getIndex">getIndex</a></li><li><a href="LunrSearch.html#.importIndex">importIndex</a></li><li><a href="LunrSearch.html#.isSupported">isSupported</a></li><li><a href="LunrSearch.html#.postIndex">postIndex</a></li><li><a href="LunrSearch.html#.search">search</a></li><li><a href="LunrSearch.html#buildIndex">buildIndex</a></li><li><a href="LunrSearch.html#exportIndex">exportIndex</a></li><li><a href="LunrSearch.html#fetch">fetch</a></li><li><a href="LunrSearch.html#getIndex">getIndex</a></li><li><a href="LunrSearch.html#importIndex">importIndex</a></li><li><a href="LunrSearch.html#postIndex">postIndex</a></li><li><a href="LunrSearch.html#search">search</a></li></ul><div class="member-type">Typedef</div><ul class="inner"><li><a href="LunrSearch.html#.Plugin">Plugin</a></li><li><a href="LunrSearch.html#.Result">Result</a></li></ul></div></li></ul></div><div class="lnb-api hidden"><h3>Namespaces</h3><ul><li><a href="plugin.html">plugin</a><button type="button" class="hidden toggle-subnav btn btn-link"> <span class="glyphicon glyphicon-plus"></span></button><div class="hidden" id="plugin_sub"></div></li><li><a href="plugin.freshdesk.html">plugin.freshdesk</a><button type="button" class="hidden toggle-subnav btn btn-link"> <span class="glyphicon glyphicon-plus"></span></button><div class="hidden" id="plugin.freshdesk_sub"><div class="member-type">Methods</div><ul class="inner"><li><a href="plugin.freshdesk.html#.fetch">fetch</a></li><li><a href="plugin.freshdesk.html#.isSupported">isSupported</a></li><li><a href="plugin.freshdesk.html#.plugin">plugin</a></li><li><a href="plugin.freshdesk.html#.process">process</a></li></ul></div></li><li><a href="util.html">util</a><button type="button" class="hidden toggle-subnav btn btn-link"> <span class="glyphicon glyphicon-plus"></span></button><div class="hidden" id="util_sub"><div class="member-type">Methods</div><ul class="inner"><li><a href="util.html#.definedFunction">definedFunction</a></li></ul></div></li></ul></div> </nav> <div id="resizer"></div> <div class="main" id="main"> <section> <article> <pre class="prettyprint source linenums"><code>import axios from 'axios' import lunr from 'lunr' import {freshdesk} from './plugin' import * as util from './util' import {version as packageVersion} from '../package.json' import flatten from 'array-flatten' let documentStorage = {} /** * @typedef Plugin * @memberOf LunrSearch * @property {Function} plugin a lunr builder plugin * @property {Function} fetch a function to fetch documents * @property {Function} isSupported checks whether the plugin is supported in the current environment */ /** * @typedef Result * @memberOf LunrSearch * @property {Object} document the document that was matched * @property {Object} source describes the source of the document * @property {string} source.type the type of the document source, examples are 'forum' or 'solution' * @property {string} source.url the URL that the document was fetched from * @property {lunr.Index~Result} result the lunr search result */ /** * A class to handle building, importing, exporting, and searching a lunr index. * It contains static and instance methods of each function so you can choose how to use it. * * @example &lt;caption>Instance usage&lt;/caption> * const builder = new lunr.Builder() // if you need to, * builder.metadataWhitelist = ['tags'] // you can customize the builder that will be used internally * * const lunrSearch = new LunrSearch('myfreshdeskdomain', 'freshdeskusername', 'freshdeskpassword', { * builder, // pass the custom builder if needed * plugins: [myCustomBuilderPlugin], * editDistance: 2 // in case your users can't type very well :) * }) * * lunrSearch.buildIndex().then(() => mySearchBar.addEventListener('input', () => lunrSeach.search(mySearchBar.value)) * * @example &lt;caption>Static usage&lt;/caption> * const opts = {domain: 'freshdeskdomain', user: 'username', pass: 'password'} * const builder = new lunr.Builder() // custom builder, etc. * const indexPromise = LunrSearch.buildIndex({builder, ...opts}) // you can pass a custom builder into the static methods too * * indexPromise.then(() => mySearchBar.addEventListener('input', () => lunrSeach.search(mySearchBar.value)) * * @param {string} domain the domain to use for all fetch requests * @param {string} user the username to use for all fetch requests * @param {string} pass the password to use for all fetch requests * @param {object} [options={}] * @param {lunr.Builder} [options.builder] a custom builder to use instead of creating a new instance * @param {Plugin[]} [options.plugins] a list of plugins to use * @param {number} [options.editDistance=1] a default edit distance to use in search queries * @class LunrSearch */ export default class LunrSearch { constructor (domain, user, pass, { builder = new lunr.Builder(), plugins = [freshdesk], editDistance = 1 } = {}) { /** * The package version. * @memberOf LunrSearch * @member {string} VERSION * @static */ this.constructor.VERSION = packageVersion /** * the fetched documents * the keys are the document ID and the value is the document. * useful for getting info about a search result. * * @memberOf LunrSearch * @member {Object} docs * @instance */ this.docs = {} /** * the domain to use for all fetch requests * * @member {string} domain * @memberOf LunrSearch * @instance */ this.domain = domain /** * the username to use for all fetch requests * * @member {string} user * @memberOf LunrSearch * @instance */ this.user = user /** * the password to use for all fetch requests * * @member {string} pass * @memberOf LunrSearch * @instance */ this.pass = pass /** * a custom builder to use * * @member {lunr.Builder} builder * @memberOf LunrSearch * @instance */ this.builder = builder /** * a list of plugins to use * * @member {Plugin[]} plugins * @memberOf LunrSearch * @instance */ this.plugins = plugins /** * a default edit distance to use in search queries * * @member {number} editDistance * @memberOf LunrSearch * @default 0 * @instance */ this.editDistance = editDistance /** * The built lunr index. * * @member {lunr.Index} index * @memberOf LunrSearch * @instance */ this.index = null } /** * Searches the index with the given query. * * @param {string} query the query to search with * @param {Object} [options={}] * @param {number} [options.editDistance] the edit distance to use for the search * @return {Result[]} an array of search results * @memberOf LunrSearch * @instance */ search (query, {editDistance} = {}) { return query ? util.buildResults(this.index.search(`${query}~${editDistance || this.editDistance}`), this.docs) : [] } /** * Gets and imports an index fram a URL. * * @async * @param {string} url the URL of the endpoint * @param {Object} [auth={}] authentication details for the API * @param {string} [auth.user] the username for the API * @param {string} [auth.pass] the password for the API * @return {lunr.Index} * @memberOf LunrSearch * @instance */ async getIndex (url, {user, pass} = {}) { this.index = await this.constructor.getIndex(url, {user, pass}) return this.index } /** * Imports an exported lunr index and stores it. * * @param {string} json the index to import as a json string * @return {void} * @memberOf LunrSearch * @instance */ importIndex (json) { this.index = this.constructor.importIndex(json) } /** * Posts index to a URL. * If the index exists locally, it will not be built. Call {@link LunrSearch#buildIndex} to build a fresh index. * If the index does not already exist, it will be built asynchronously. * * @async * @param {string} url the URL of the endpoint * @param {Object} [auth={}] authentication details for the API * @param {string} [auth.user] the username for the API * @param {string} [auth.pass] the password for the API * @return {axios.Response} * @memberOf LunrSearch * @instance */ async postIndex (url, {user, pass} = {}) { return this.constructor.postIndex(await this.exportIndex(), url, {user, pass}) } /** * Serializes and exports a lunr index. * If the index exists locally, it will not be built. Call #buildIndex to build a fresh index. * If the index does not already exist, it will be built asynchronously. * * @async * @return {Promise&lt;string>} the serialized index * @memberOf LunrSearch * @instance */ async exportIndex () { return JSON.stringify(this.index || await this.buildIndex()) } /** * Builds an index and stores it. * * @async * @return {lunr.Index} the built index * @memberOf LunrSearch * @instance */ async buildIndex () { const docs = Object.values(this.docs) this.index = await this.constructor.buildIndex({ docs: docs.length > 0 ? docs : await this.fetch(), builder: this.builder, plugins: this.plugins }) return this.index } /** * Fetches some documents that are ready to be indexed. * * @async * @return {Object[]} the array of Objects to be indexed * @memberOf LunrSearch * @instance */ async fetch () { const docs = await this.constructor.fetch({ domain: this.domain, user: this.user, pass: this.pass, plugins: this.plugins }) this.docs = documentStorage return docs } /** * Searches the given index with the given query. * If query is falsey no search is performed. * * @param {string} query the query to search with * @param {lunr.Index} index an index to use for the search * @param {Object} [options={}] * @param {number} [options.editDistance=1] the edit distance to use for the search * @return {Result[]} an array of search results * @memberOf LunrSearch * @static */ static search (query, index, {editDistance = 1}) { return query ? util.buildResults(index.search(`${query}~${editDistance}`), documentStorage) : [] } /** * Gets and imports an index fram a URL. * * @async * @param {string} url the URL of the endpoint * @param {Object} [auth={}] authentication details for the API * @param {string} [auth.user] the username for the API * @param {string} [auth.pass] the password for the API * @return {lunr.Index} * @memberOf LunrSearch * @static */ static async getIndex (url, {user, pass} = {}) { return axios.get(url, {auth: {username: user, password: pass}}).then(({data}) => this.importIndex(data)) } /** * Imports an exported lunr index and returns it. * * @param {string} json the stringified index to import * @return {lunr.Index} * @memberOf LunrSearch * @static */ static importIndex (json) { return lunr.Index.load(JSON.parse(json)) } /** * Posts an exported index to a URL. * * @async * @param {lunr.Index} index the index to be posted * @param {string} url the URL of the endpoint * @param {Object} [auth={}] authentication details for the API * @param {string} [auth.user] the username for the API * @param {string} [auth.pass] the password for the API * @return {axios.Response} * @memberOf LunrSearch * @static */ static async postIndex (index, url, {user, pass} = {}) { return axios.post(url, index, {auth: {username: user, password: pass}}) } /** * Builds then serializes and exports a lunr index. * * @async * @param {Object} [options={}] * @param {string} [options.domain] the domain of the API to make the request to * @param {string} [options.user] the username for the API * @param {string} [options.pass] the password for the API * @param {lunr.Builder} [options.builder] the builder to use for building the index * @param {Function[]} [options.plugins] a list of plugins for the builder to use * @return {string} the serialized index * @memberOf LunrSearch * @static */ static async exportIndex ({ domain, user, pass, builder = new lunr.Builder(), plugins = [freshdesk] }) { return JSON.stringify(await this.buildIndex({domain, user, pass, builder, plugins})) } /** * Builds an index and returns it. * If no docs are supplied, they will be fetched. * * @async * @param {Object} [options={}] * @param {string} [options.domain] the domain of the API to make the request to * @param {string} [options.user] the username for the API * @param {string} [options.pass] the password for the API * @param {Object[]} [options.docs] list of docs to build the index with * @param {lunr.Builder} [options.builder] the builder to use for building the index * @param {Plugin[]} [options.plugins] a list of plugins * @return {lunr.Index} the built index * @memberOf LunrSearch * @static */ static async buildIndex ({ domain, user, pass, docs: _docs, builder = new lunr.Builder(), plugins = [freshdesk] }) { plugins.forEach(p => builder.use(p.plugin)) const docs = _docs || await this.fetch({domain, user, pass}) docs.forEach(doc => builder.add(doc)) return builder.build() } /** * Fetches some documents that are ready to be indexed. * * @async * @param {Object} [options={}] * @param {string} [options.domain] the domain of the API to make the request to * @param {string} [options.user] the username for the API * @param {string} [options.pass] the password for the API * @param {Plugin[]} [options.plugins] a list of plugins * @return {Object[]} the array of Objects to be indexed * @memberOf LunrSearch * @static */ static async fetch ({ domain, user, pass, plugins = [freshdesk] }) { return new Promise((resolve, reject) => { const docs = [] Promise.all(plugins.map(plugin => plugin.fetch(domain, user, pass).then(d => d.forEach(doc => { docs.push(doc) documentStorage[doc.id] = doc })))).then(() => resolve(docs)) }) } /** * Checks to see if certain functions are defined. * * @param {Plugin[]} [plugins] a list of plugins * @return {Boolean} * @memberOf LunrSearch * @static */ static isSupported (plugins = [freshdesk]) { let supported = true plugins.forEach(plugin => { supported = supported &amp;&amp; plugin.isSupported() }) supported = supported &amp;&amp; util.definedFunction([].forEach) return supported } } </code></pre> </article> </section> </div> <footer> <img class="logo" src="img/toast-ui.png" style=""> <div class="footer-text">made this awesome JSDoc theme!</div> </footer> <script>prettyPrint();</script> <script src="scripts/jquery.min.js"></script> <script src="scripts/tui-doc.js"></script> <script src="scripts/linenumber.js"></script> <script> var id = '_sub'.replace(/"/g, '_'); var selectedApi = document.getElementById(id); // do not use jquery selector var $selectedApi = $(selectedApi); $selectedApi.removeClass('hidden'); $selectedApi.parent().find('.glyphicon').removeClass('glyphicon-plus').addClass('glyphicon-minus'); showLnbApi(); </script> </body> </html>