lunr-elastic-search
Version:
Uses Lunr.js to index and search the knowledge base.
505 lines (447 loc) • 18.3 kB
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 <caption>Instance usage</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 <caption>Static usage</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<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 && plugin.isSupported() })
supported = supported && 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>