initial vitepress site with basic nav

This commit is contained in:
mrflos 2023-05-20 19:37:42 +03:00
parent a7df2e049d
commit 2029f16583
1900 changed files with 1014692 additions and 0 deletions

398
node_modules/minisearch/CHANGELOG.md generated vendored Normal file
View file

@ -0,0 +1,398 @@
# Changelog
`MiniSearch` follows [semantic versioning](https://semver.org/spec/v2.0.0.html).
# v6.1.0
- Add `getStoredFields` method to retrieve the stored fields for a document
given its ID.
- Pass stored fields to the `boostDocument` callback function, making it
easier to perform dynamic document boosting.
# v6.0.1
- [fix] The `boost` search option now does not interfere with the `fields`
search option: if `fields` is specified, boosting a field that is not
included in `fields` has no effect, and will not include such boosted field
in the search.
- [fix] When using `search` with a `QuerySpec`, the `combineWith` option is
now properly taking its default from the `SearchOptions` given as the second
argument.
# v6.0.0
This is a major release. The most notable change is the addition of `discard`,
`discardAll`, and `replace`. These method make it more convenient and performant
to remove or replace documents.
This release is almost completely backwards compatible with `v5`, apart from one
breaking change in the behavior of `add` when the document ID already exists.
Changes:
- [breaking change] `add`, `addAll`, and `addAllAsync` now throw an error on
duplicate document IDs. When necessary, it is now possible to check for the
existence of a document with a certain ID with the new method `has`.
- Add `discard` method to remove documents by ID. This is a convenient
alternative to `remove` that takes only the ID of the documents to remove,
as opposed to the whole document. The visible effect is the same as
`remove`. The difference is that `remove` immediately mutates the index,
while `discard` marks the current document version as discarded, so it is
immedately ignored by searches, but delays modifying the index until a
certain number of documents are discarded. At that point, a vacuuming is
triggered, cleaning up the index from obsolete references and allowing
memory to be released.
- Add `discardAll` and `replace` methods, built on top of `discard`
- Add vacuuming of references to discarded documents from the index. Vacuuming
is performed automatically by default when the number of discarded documents
reaches a threshold (controlled by the new `autoVacuum` constructor option),
or can be triggered manually by calling the `vacuum` method. The new
`dirtCount` and `dirtFactor` properties give the current value of the
parameters used to decide whether to trigger an automatic vacuuming.
- Add `termCount` property, giving the number of distinct terms present in the
index
- Allow customizing the parameters of the BM25+ scoring algorithm via the
`bm25` search option.
- Improve TypeScript type of some methods by marking the given array argument
as `readonly`, signaling that it won't be mutated, and allowing passing
readonly arrays.
- Make it possible to overload the `loadJS` static method in subclasses
# v5.1.0
- The `processTerm` option can now also expand a single term into several
terms by returning an array of strings.
- Add `logger` option to pass a custom logger function.
# v5.0.0
This is a major release. The main change is an improved scoring algorithm based
on [BM25+](https://en.wikipedia.org/wiki/Okapi_BM25). The new algorithm will
cause the scoring and sorting of search results to be different than in previous
versions (generally better), and need less aggressive boosting.
- [breaking change] Use the [BM25+
algorithm](https://en.wikipedia.org/wiki/Okapi_BM25) to score search
results, improving their quality over the previous implementation. Note
that, if you were using field boosting, you might need to re-adjust the
boosting amounts, since their effect is now different.
- [breaking change] auto suggestions now default to `combineWith: 'AND'`
instead of `'OR'`, requiring all the query terms to match. The old defaults
can be replicated by passing a new `autoSuggestOptions` option to the
constructor, with value `{ autoSuggestOptions: { combineWith: 'OR' } }`.
- Possibility to set the default auto suggest options in the constructor.
- Remove redundant fields in the index data. This also changes the
serialization format, but serialized indexes created with `v4.x.y` are still
deserialized correctly.
- Define `exports` entry points in `package.json`, to require MiniSearch as a
commonjs package or import it as a ES module.
# v4.0.3
- [fix] Fix regression causing stored fields not being saved in some
situations.
# v4.0.2
- [fix] Fix match data on mixed prefix and fuzzy search
# v4.0.1
- [fix] Fix an issue with scoring, causing a result matching both fuzzy and
prefix search to be scored higher than an exact match.
- [breaking change] `SearchableMap` method `fuzzyGet` now returns a `Map`
instead of an object. This is a breaking change only if you directly use
`SearchableMap`, not if you use `MiniSearch`, and is considered part of
version 4.
# v4.0.0
- [breaking change] The serialization format was changed, to abstract away the
internal implementation details of the index data structure. This allows for
present and future optimizations without breaking backward compatibility
again. Moreover, the new format is simpler, facilitating the job of tools
that create a serialized MiniSearch index in other languages.
- [performance] Large performance improvements on indexing (at least 4 time
faster in the official benchmark) and search, due to changes to the internal
data structures and the code.
- [peformance] The fuzzy search algorithm has been updated to work like
outlined in [this blog post by Steve
Hanov](http://stevehanov.ca/blog/?id=114), improving its performance by
several times, especially on large maximum edit distances.
- [fix] The `weights` search option did not have an effect due to a bug. Now
it works as documented. Note that, due to this, the relative scoring of
fuzzy vs. prefix search matches might change compared to previous versions.
This change also brings a further performance improvement of both fuzzy and
prefix search.
**Migration notes:**
If you have an index serialized with a previous version of MiniSearch, you will
need to re-create it when you upgrade to MiniSearch `v4`.
Also note that loading a pre-serialized index is _slower_ in `v4` than in
previous versions, but there are much larger performance gains on indexing and
search speed. If you serialized an index on the server-side, it is worth
checking if it is now fast enough for your use case to index on the client side:
it would save you from having to re-serialize the index every time something
changes.
**Acknowledgements:**
Many thanks to [rolftimmermans](https://github.com/rolftimmermans) for
contributing the fixes and outstanding performance improvements that are part of
this release.
# v3.3.0
- Add `maxFuzzy` search option, to limit the maximum edit distance for fuzzy
search when using fractional fuzziness
# v3.2.0
- Add AND_NOT combinator to subtract results of a subquery from another (for
example to find documents that match one term and not another)
# v3.1.0
- Add possibility for advanced combination of subqueries as query expression
trees
# v3.0.4
- [fix] Keep radix tree property (no node with a single child) after removal
of an entry
# v3.0.3
- [fix] Adjust data about field lengths upon document removal
# v3.0.2
- [fix] `addAllAsync` now allows events to be processed between chunks, avoid
blocking the UI (by [@grimmen](https://github.com/grimmen))
# v3.0.1
- [fix] Fix type signature of `removeAll` to allow calling it with no
arguments. Also, throw a more informative error if called with a falsey
value. Thanks to [https://github.com/nilclass](@nilclass).
# v3.0.0
This major version ports the source code to TypeScript. That made it possible
to improve types and documentation, making sure that both are in sync with the
actual code. It is mostly backward compatible: JavaScript users should
experience no breaking change, while TypeScript users _might_ have toadapt
some types.
- Port source to [TypeScript](https://www.typescriptlang.org), adding type
safety
- Improved types and documentation (now generated with [TypeDoc](http://typedoc.org))
- [breaking change, fix] TypeScript `SearchOptions` type is not generic
anymore
- [breaking change] `SearchableMap` is not a static field of `MiniSearch`
anymore: it can instead be imported separately as `minisearch/SearchableMap`
# v2.6.2
- [fix] Improve TypeScript types: default generic document type is `any`, not `object`
# v2.6.1
- No change from 2.6.0
# v2.6.0
- Better TypeScript typings using generics, letting the user (optionally)
specify the document type.
# v2.5.1
- [fix] Fix document removal when using a custom `extractField` function
(thanks [@ahri](https://github.com/ahri) for reporting and reproducting)
# v2.5.0
- Make `idField` extraction customizeable and consistent with other fields,
using `extractField`
# v2.4.1
- [fix] Fix issue with the term `constructor` (reported by
[@scambier](https://github.com/scambier))
- [fix] Fix issues when a field is named like a default property of JavaScript
objects
# v2.4.0
- Convert field value to string before tokenization and indexing. This makes
a custom field extractor unnecessary for basic cases like integers or simple
arrays.
# v2.3.1
- Version `v2.3.1` mistakenly did not contain the commit adding `removeAll`,
this patch release fixes it.
# v2.3.0
- Add `removeAll` method, to remove many documents, or all documents, at once.
# v2.2.2
- Avoid destructuring variables named with an underscore prefix. This plays
nicer to some common minifier and builder configurations.
- Performance improvement in `getDefault` (by
[stalniy](https://github.com/stalniy))
- Fix the linter setup, to ensure code style consistency
## v2.2.1
- Add `"sideEffects": false` to `package.json` to allow bundlers to perform
tree shaking
## v2.2.0
- [fix] Fix documentation of `SearchableMap.prototype.atPrefix` (by
[@graphman65](https://github.com/graphman65))
- Switch to Rollup for bundling (by [stalniy](https://github.com/stalniy)),
reducing size of build and providing ES6 and ES5 module versions too.
## v2.1.4
- [fix] Fix document removal in presence of custom per field tokenizer, field
extractor, or term processor (thanks [@CaptainChaos](https://github.com/CaptainChaos))
## v2.1.3
- [fix] Fix TypeScript definition for `storeFields` option (by
[@ryan-codingintrigue](https://github.com/ryan-codingintrigue))
## v2.1.2
- [fix] Fix TypeScript definition for `fuzzy` option (by
[@alessandrobardini](https://github.com/alessandrobardini))
## v2.1.1
- [fix] Fix TypeScript definitions adding `filter` and `storeFields` options
(by [@emilianox](https://github.com/emilianox))
## v2.1.0
- [feature] Add support for stored fields
- [feature] Add filtering of search results and auto suggestions
## v2.0.6
- Better TypeScript definitions (by [@samuelmeuli](https://github.com/samuelmeuli))
## v2.0.5
- Add TypeScript definitions for ease of use in TypeScript projects
## v2.0.4
- [fix] tokenizer behavior with newline characters (by [@samuelmeuli](https://github.com/samuelmeuli))
## v2.0.3
- Fix small imprecision in documentation
## v2.0.2
- Add `addAllAsync` method, adding many documents asynchronously and in chunks
to avoid blocking the main thread
## v2.0.1
- Throw a more descriptive error when `loadJSON` is called without options
## v2.0.0
This release introduces better defaults. It is considered a major release, as
the default options are slightly different, but the API is not changed.
- *Breaking change*: default tokenizer splits by Unicode space or punctuation
(before it was splitting by space, punctuation, or _symbol_). The difference
is that currency symbols and other non-punctuation symbols will not be
discarded: "it's 100€" is now tokenized as `["it", "s", "100€"]` instead of
`["it", "s", "100"]`.
- *Breaking change*: default term processing does not discard 1-character
words.
- *Breaking change*: auto suggestions by default perform prefix search only on
the last term in the query. So "super cond" will suggest "super
conductivity", but not "superposition condition".
## v1.3.1
- Better and more compact regular expression in the default tokenizer,
separating on Unicode spaces, punctuation, and symbols
## v1.3.0
- Support for non-latin scripts
## v1.2.1
- Improve fuzzy search performance (common cases are now ~4x faster, as shown
by the benchmark)
## v1.2.0
- Add possibility to configure a custom field extraction function by setting
the `extractField` option (to support cases like nested fields, non-string
fields, getter methods, field pre-processing, etc.)
## v1.1.2
- Add `getDefault` static method to get the default value of configuration options
## v1.1.1
- Do not minify library when published as NPM package. Run `yarn
build-minified` (or `npm run build-minified`) to produce a minified build
with source maps.
- **Bugfix**: as per specification, `processTerm` is called with only one
argument upon search (see [#5](https://github.com/lucaong/minisearch/issues/5))
## v1.1.0
- Add possibility to configure separate index-time and search-time
tokenization and term processing functions
- The `processTerm` function can now reject a term by returning a falsy value
- Upon indexing, the `tokenize` and `processTerm` functions receive the field
name as the second argument. This makes it possible to process or tokenize
each field differently.
## v1.0.1
- Reduce bundle size by optimizing babel preset env options
## v1.0.0
Production-ready release.
Features:
- Space-optimized index
- Exact match, prefix match, fuzzy search
- Auto suggestions
- Add/remove documents at any time

7
node_modules/minisearch/LICENSE.txt generated vendored Normal file
View file

@ -0,0 +1,7 @@
Copyright 2022 Luca Ongaro
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

346
node_modules/minisearch/README.md generated vendored Normal file
View file

@ -0,0 +1,346 @@
# MiniSearch
[![CI Build](https://github.com/lucaong/minisearch/workflows/CI%20Build/badge.svg)](https://github.com/lucaong/minisearch/actions)
[![Coverage Status](https://coveralls.io/repos/github/lucaong/minisearch/badge.svg?branch=master)](https://coveralls.io/github/lucaong/minisearch?branch=master)
[![Minzipped Size](https://badgen.net/bundlephobia/minzip/minisearch)](https://bundlephobia.com/result?p=minisearch)
[![npm](https://img.shields.io/npm/v/minisearch?color=%23ff00dd)](https://www.npmjs.com/package/minisearch)
[![npm downloads](https://img.shields.io/npm/dw/minisearch)](https://www.npmjs.com/package/minisearch)
[![types](https://img.shields.io/npm/types/minisearch)](https://lucaong.github.io/minisearch/classes/_minisearch_.minisearch.html)
`MiniSearch` is a tiny but powerful in-memory fulltext search engine written in
JavaScript. It is respectful of resources, and it can comfortably run both in
Node and in the browser.
Try out the [demo application](https://lucaong.github.io/minisearch/examples/).
Find the complete [documentation and API reference
here](https://lucaong.github.io/minisearch/classes/_minisearch_.minisearch.html),
and more background about `MiniSearch`, including a comparison with other
similar libraries, in [this blog
post](https://lucaongaro.eu/blog/2019/01/30/minisearch-client-side-fulltext-search-engine.html).
`MiniSearch` follows [semantic versioning](https://semver.org/spec/v2.0.0.html),
and documents releases and changes in the
[changelog](https://github.com/lucaong/minisearch/blob/master/CHANGELOG.md).
## Use case
`MiniSearch` addresses use cases where full-text search features are needed
(e.g. prefix search, fuzzy search, ranking, boosting of fields…), but the data
to be indexed can fit locally in the process memory. While you won't index the
whole Internet with it, there are surprisingly many use cases that are served
well by `MiniSearch`. By storing the index in local memory, `MiniSearch` can
work offline, and can process queries quickly, without network latency.
A prominent use-case is real time search "as you type" in web and mobile
applications, where keeping the index on the client enables fast and reactive
UIs, removing the need to make requests to a search server.
## Features
* Memory-efficient index, designed to support memory-constrained use cases
like mobile browsers.
* Exact match, prefix search, fuzzy match, field boosting.
* Auto-suggestion engine, for auto-completion of search queries.
* Modern search result ranking algorithm.
* Documents can be added and removed from the index at any time.
* Zero external dependencies.
`MiniSearch` strives to expose a simple API that provides the building blocks to
build custom solutions, while keeping a small and well tested codebase.
## Installation
With `npm`:
```
npm install minisearch
```
With `yarn`:
```
yarn add minisearch
```
Then `require` or `import` it in your project:
```javascript
// If you are using import:
import MiniSearch from 'minisearch'
// If you are using require:
const MiniSearch = require('minisearch')
```
Alternatively, if you prefer to use a `<script>` tag, you can require MiniSearch
[from a CDN](https://www.jsdelivr.com/package/npm/minisearch):
```html
<script src="https://cdn.jsdelivr.net/npm/minisearch@6.1.0/dist/umd/index.min.js"></script>
```
In this case, `MiniSearch` will appear as a global variable in your project.
Finally, if you want to manually build the library, clone the repository and run
`yarn build` (or `yarn build-minified` for a minified version + source maps).
The compiled source will be created in the `dist` folder (UMD, ES6 and ES2015
module versions are provided).
## Usage
### Basic usage
```javascript
// A collection of documents for our examples
const documents = [
{
id: 1,
title: 'Moby Dick',
text: 'Call me Ishmael. Some years ago...',
category: 'fiction'
},
{
id: 2,
title: 'Zen and the Art of Motorcycle Maintenance',
text: 'I can see by my watch...',
category: 'fiction'
},
{
id: 3,
title: 'Neuromancer',
text: 'The sky above the port was...',
category: 'fiction'
},
{
id: 4,
title: 'Zen and the Art of Archery',
text: 'At first sight it must seem...',
category: 'non-fiction'
},
// ...and more
]
let miniSearch = new MiniSearch({
fields: ['title', 'text'], // fields to index for full-text search
storeFields: ['title', 'category'] // fields to return with search results
})
// Index all documents
miniSearch.addAll(documents)
// Search with default options
let results = miniSearch.search('zen art motorcycle')
// => [
// { id: 2, title: 'Zen and the Art of Motorcycle Maintenance', category: 'fiction', score: 2.77258, match: { ... } },
// { id: 4, title: 'Zen and the Art of Archery', category: 'non-fiction', score: 1.38629, match: { ... } }
// ]
```
### Search options
`MiniSearch` supports several options for more advanced search behavior:
```javascript
// Search only specific fields
miniSearch.search('zen', { fields: ['title'] })
// Boost some fields (here "title")
miniSearch.search('zen', { boost: { title: 2 } })
// Prefix search (so that 'moto' will match 'motorcycle')
miniSearch.search('moto', { prefix: true })
// Search within a specific category
miniSearch.search('zen', {
filter: (result) => result.category === 'fiction'
})
// Fuzzy search, in this example, with a max edit distance of 0.2 * term length,
// rounded to nearest integer. The mispelled 'ismael' will match 'ishmael'.
miniSearch.search('ismael', { fuzzy: 0.2 })
// You can set the default search options upon initialization
miniSearch = new MiniSearch({
fields: ['title', 'text'],
searchOptions: {
boost: { title: 2 },
fuzzy: 0.2
}
})
miniSearch.addAll(documents)
// It will now by default perform fuzzy search and boost "title":
miniSearch.search('zen and motorcycles')
```
### Auto suggestions
`MiniSearch` can suggest search queries given an incomplete query:
```javascript
miniSearch.autoSuggest('zen ar')
// => [ { suggestion: 'zen archery art', terms: [ 'zen', 'archery', 'art' ], score: 1.73332 },
// { suggestion: 'zen art', terms: [ 'zen', 'art' ], score: 1.21313 } ]
```
The `autoSuggest` method takes the same options as the `search` method, so you
can get suggestions for misspelled words using fuzzy search:
```javascript
miniSearch.autoSuggest('neromancer', { fuzzy: 0.2 })
// => [ { suggestion: 'neuromancer', terms: [ 'neuromancer' ], score: 1.03998 } ]
```
Suggestions are ranked by the relevance of the documents that would be returned
by that search.
Sometimes, you might need to filter auto suggestions to, say, only a specific
category. You can do so by providing a `filter` option:
```javascript
miniSearch.autoSuggest('zen ar', {
filter: (result) => result.category === 'fiction'
})
// => [ { suggestion: 'zen art', terms: [ 'zen', 'art' ], score: 1.21313 } ]
```
### Field extraction
By default, documents are assumed to be plain key-value objects with field names
as keys and field values as simple values. In order to support custom field
extraction logic (for example for nested fields, or non-string field values that
need processing before tokenization), a custom field extractor function can be
passed as the `extractField` option:
```javascript
// Assuming that our documents look like:
const documents = [
{ id: 1, title: 'Moby Dick', author: { name: 'Herman Melville' }, pubDate: new Date(1851, 9, 18) },
{ id: 2, title: 'Zen and the Art of Motorcycle Maintenance', author: { name: 'Robert Pirsig' }, pubDate: new Date(1974, 3, 1) },
{ id: 3, title: 'Neuromancer', author: { name: 'William Gibson' }, pubDate: new Date(1984, 6, 1) },
{ id: 4, title: 'Zen in the Art of Archery', author: { name: 'Eugen Herrigel' }, pubDate: new Date(1948, 0, 1) },
// ...and more
]
// We can support nested fields (author.name) and date fields (pubDate) with a
// custom `extractField` function:
let miniSearch = new MiniSearch({
fields: ['title', 'author.name', 'pubYear'],
extractField: (document, fieldName) => {
// If field name is 'pubYear', extract just the year from 'pubDate'
if (fieldName === 'pubYear') {
const pubDate = document['pubDate']
return pubDate && pubDate.getFullYear().toString()
}
// Access nested fields
return fieldName.split('.').reduce((doc, key) => doc && doc[key], document)
}
})
```
The default field extractor can be obtained by calling
`MiniSearch.getDefault('extractField')`.
### Tokenization
By default, documents are tokenized by splitting on Unicode space or punctuation
characters. The tokenization logic can be easily changed by passing a custom
tokenizer function as the `tokenize` option:
```javascript
// Tokenize splitting by hyphen
let miniSearch = new MiniSearch({
fields: ['title', 'text'],
tokenize: (string, _fieldName) => string.split('-')
})
```
Upon search, the same tokenization is used by default, but it is possible to
pass a `tokenize` search option in case a different search-time tokenization is
necessary:
```javascript
// Tokenize splitting by hyphen
let miniSearch = new MiniSearch({
fields: ['title', 'text'],
tokenize: (string) => string.split('-'), // indexing tokenizer
searchOptions: {
tokenize: (string) => string.split(/[\s-]+/) // search query tokenizer
}
})
```
The default tokenizer can be obtained by calling
`MiniSearch.getDefault('tokenize')`.
### Term processing
Terms are downcased by default. No stemming is performed, and no stop-word list
is applied. To customize how the terms are processed upon indexing, for example
to normalize them, filter them, or to apply stemming, the `processTerm` option
can be used. The `processTerm` function should return the processed term as a
string, or a falsy value if the term should be discarded:
```javascript
let stopWords = new Set(['and', 'or', 'to', 'in', 'a', 'the', /* ...and more */ ])
// Perform custom term processing (here discarding stop words and downcasing)
let miniSearch = new MiniSearch({
fields: ['title', 'text'],
processTerm: (term, _fieldName) =>
stopWords.has(term) ? null : term.toLowerCase()
})
```
By default, the same processing is applied to search queries. In order to apply
a different processing to search queries, supply a `processTerm` search option:
```javascript
let miniSearch = new MiniSearch({
fields: ['title', 'text'],
processTerm: (term) =>
stopWords.has(term) ? null : term.toLowerCase(), // index term processing
searchOptions: {
processTerm: (term) => term.toLowerCase() // search query processing
}
})
```
The default term processor can be obtained by calling
`MiniSearch.getDefault('processTerm')`.
### API Documentation
Refer to the [API
documentation](https://lucaong.github.io/minisearch/classes/_minisearch_.minisearch.html)
for details about configuration options and methods.
## Browser compatibility
`MiniSearch` natively supports all modern browsers implementing JavaScript
standards, but requires a polyfill when used in Internet Explorer, as it makes
use functions like `Object.entries`, `Array.includes`, and `Array.from`, which
are standard but not available on older browsers. The package
[`core-js`](https://github.com/zloirock/core-js) is one such polyfill that can
be used to provide those functions.
## Contributing
Contributions to `MiniSearch` are welcome! Please read the [contributions
guidelines](https://github.com/lucaong/minisearch/blob/master/CONTRIBUTING.md).
Reading the [design
document](https://github.com/lucaong/minisearch/blob/master/DESIGN_DOCUMENT.md) is
also useful to understand the project goals and the technical implementation.

680
node_modules/minisearch/dist/cjs/SearchableMap.cjs generated vendored Normal file
View file

@ -0,0 +1,680 @@
'use strict';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
}
/** @ignore */
var ENTRIES = 'ENTRIES';
/** @ignore */
var KEYS = 'KEYS';
/** @ignore */
var VALUES = 'VALUES';
/** @ignore */
var LEAF = '';
/**
* @private
*/
var TreeIterator = /** @class */ (function () {
function TreeIterator(set, type) {
var node = set._tree;
var keys = Array.from(node.keys());
this.set = set;
this._type = type;
this._path = keys.length > 0 ? [{ node: node, keys: keys }] : [];
}
TreeIterator.prototype.next = function () {
var value = this.dive();
this.backtrack();
return value;
};
TreeIterator.prototype.dive = function () {
if (this._path.length === 0) {
return { done: true, value: undefined };
}
var _a = last$1(this._path), node = _a.node, keys = _a.keys;
if (last$1(keys) === LEAF) {
return { done: false, value: this.result() };
}
var child = node.get(last$1(keys));
this._path.push({ node: child, keys: Array.from(child.keys()) });
return this.dive();
};
TreeIterator.prototype.backtrack = function () {
if (this._path.length === 0) {
return;
}
var keys = last$1(this._path).keys;
keys.pop();
if (keys.length > 0) {
return;
}
this._path.pop();
this.backtrack();
};
TreeIterator.prototype.key = function () {
return this.set._prefix + this._path
.map(function (_a) {
var keys = _a.keys;
return last$1(keys);
})
.filter(function (key) { return key !== LEAF; })
.join('');
};
TreeIterator.prototype.value = function () {
return last$1(this._path).node.get(LEAF);
};
TreeIterator.prototype.result = function () {
switch (this._type) {
case VALUES: return this.value();
case KEYS: return this.key();
default: return [this.key(), this.value()];
}
};
TreeIterator.prototype[Symbol.iterator] = function () {
return this;
};
return TreeIterator;
}());
var last$1 = function (array) {
return array[array.length - 1];
};
/**
* @ignore
*/
var fuzzySearch = function (node, query, maxDistance) {
var results = new Map();
if (query === undefined)
return results;
// Number of columns in the Levenshtein matrix.
var n = query.length + 1;
// Matching terms can never be longer than N + maxDistance.
var m = n + maxDistance;
// Fill first matrix row and column with numbers: 0 1 2 3 ...
var matrix = new Uint8Array(m * n).fill(maxDistance + 1);
for (var j = 0; j < n; ++j)
matrix[j] = j;
for (var i = 1; i < m; ++i)
matrix[i * n] = i;
recurse(node, query, maxDistance, results, matrix, 1, n, '');
return results;
};
// Modified version of http://stevehanov.ca/blog/?id=114
// This builds a Levenshtein matrix for a given query and continuously updates
// it for nodes in the radix tree that fall within the given maximum edit
// distance. Keeping the same matrix around is beneficial especially for larger
// edit distances.
//
// k a t e <-- query
// 0 1 2 3 4
// c 1 1 2 3 4
// a 2 2 1 2 3
// t 3 3 2 1 [2] <-- edit distance
// ^
// ^ term in radix tree, rows are added and removed as needed
var recurse = function (node, query, maxDistance, results, matrix, m, n, prefix) {
var e_1, _a;
var offset = m * n;
try {
key: for (var _b = __values(node.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var key = _c.value;
if (key === LEAF) {
// We've reached a leaf node. Check if the edit distance acceptable and
// store the result if it is.
var distance = matrix[offset - 1];
if (distance <= maxDistance) {
results.set(prefix, [node.get(key), distance]);
}
}
else {
// Iterate over all characters in the key. Update the Levenshtein matrix
// and check if the minimum distance in the last row is still within the
// maximum edit distance. If it is, we can recurse over all child nodes.
var i = m;
for (var pos = 0; pos < key.length; ++pos, ++i) {
var char = key[pos];
var thisRowOffset = n * i;
var prevRowOffset = thisRowOffset - n;
// Set the first column based on the previous row, and initialize the
// minimum distance in the current row.
var minDistance = matrix[thisRowOffset];
var jmin = Math.max(0, i - maxDistance - 1);
var jmax = Math.min(n - 1, i + maxDistance);
// Iterate over remaining columns (characters in the query).
for (var j = jmin; j < jmax; ++j) {
var different = char !== query[j];
// It might make sense to only read the matrix positions used for
// deletion/insertion if the characters are different. But we want to
// avoid conditional reads for performance reasons.
var rpl = matrix[prevRowOffset + j] + +different;
var del = matrix[prevRowOffset + j + 1] + 1;
var ins = matrix[thisRowOffset + j] + 1;
var dist = matrix[thisRowOffset + j + 1] = Math.min(rpl, del, ins);
if (dist < minDistance)
minDistance = dist;
}
// Because distance will never decrease, we can stop. There will be no
// matching child nodes.
if (minDistance > maxDistance) {
continue key;
}
}
recurse(node.get(key), query, maxDistance, results, matrix, i, n, prefix + key);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
};
/**
* A class implementing the same interface as a standard JavaScript
* [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
* with string keys, but adding support for efficiently searching entries with
* prefix or fuzzy search. This class is used internally by [[MiniSearch]] as
* the inverted index data structure. The implementation is a radix tree
* (compressed prefix tree).
*
* Since this class can be of general utility beyond _MiniSearch_, it is
* exported by the `minisearch` package and can be imported (or required) as
* `minisearch/SearchableMap`.
*
* @typeParam T The type of the values stored in the map.
*/
var SearchableMap = /** @class */ (function () {
/**
* The constructor is normally called without arguments, creating an empty
* map. In order to create a [[SearchableMap]] from an iterable or from an
* object, check [[SearchableMap.from]] and [[SearchableMap.fromObject]].
*
* The constructor arguments are for internal use, when creating derived
* mutable views of a map at a prefix.
*/
function SearchableMap(tree, prefix) {
if (tree === void 0) { tree = new Map(); }
if (prefix === void 0) { prefix = ''; }
this._size = undefined;
this._tree = tree;
this._prefix = prefix;
}
/**
* Creates and returns a mutable view of this [[SearchableMap]], containing only
* entries that share the given prefix.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set("unicorn", 1)
* map.set("universe", 2)
* map.set("university", 3)
* map.set("unique", 4)
* map.set("hello", 5)
*
* let uni = map.atPrefix("uni")
* uni.get("unique") // => 4
* uni.get("unicorn") // => 1
* uni.get("hello") // => undefined
*
* let univer = map.atPrefix("univer")
* univer.get("unique") // => undefined
* univer.get("universe") // => 2
* univer.get("university") // => 3
* ```
*
* @param prefix The prefix
* @return A [[SearchableMap]] representing a mutable view of the original Map at the given prefix
*/
SearchableMap.prototype.atPrefix = function (prefix) {
var e_1, _a;
if (!prefix.startsWith(this._prefix)) {
throw new Error('Mismatched prefix');
}
var _b = __read(trackDown(this._tree, prefix.slice(this._prefix.length)), 2), node = _b[0], path = _b[1];
if (node === undefined) {
var _c = __read(last(path), 2), parentNode = _c[0], key = _c[1];
try {
for (var _d = __values(parentNode.keys()), _e = _d.next(); !_e.done; _e = _d.next()) {
var k = _e.value;
if (k !== LEAF && k.startsWith(key)) {
var node_1 = new Map();
node_1.set(k.slice(key.length), parentNode.get(k));
return new SearchableMap(node_1, prefix);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
}
finally { if (e_1) throw e_1.error; }
}
}
return new SearchableMap(node, prefix);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear
*/
SearchableMap.prototype.clear = function () {
this._size = undefined;
this._tree.clear();
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete
* @param key Key to delete
*/
SearchableMap.prototype.delete = function (key) {
this._size = undefined;
return remove(this._tree, key);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries
* @return An iterator iterating through `[key, value]` entries.
*/
SearchableMap.prototype.entries = function () {
return new TreeIterator(this, ENTRIES);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/forEach
* @param fn Iteration function
*/
SearchableMap.prototype.forEach = function (fn) {
var e_2, _a;
try {
for (var _b = __values(this), _c = _b.next(); !_c.done; _c = _b.next()) {
var _d = __read(_c.value, 2), key = _d[0], value = _d[1];
fn(key, value, this);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
};
/**
* Returns a Map of all the entries that have a key within the given edit
* distance from the search key. The keys of the returned Map are the matching
* keys, while the values are two-element arrays where the first element is
* the value associated to the key, and the second is the edit distance of the
* key to the search key.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set('hello', 'world')
* map.set('hell', 'yeah')
* map.set('ciao', 'mondo')
*
* // Get all entries that match the key 'hallo' with a maximum edit distance of 2
* map.fuzzyGet('hallo', 2)
* // => Map(2) { 'hello' => ['world', 1], 'hell' => ['yeah', 2] }
*
* // In the example, the "hello" key has value "world" and edit distance of 1
* // (change "e" to "a"), the key "hell" has value "yeah" and edit distance of 2
* // (change "e" to "a", delete "o")
* ```
*
* @param key The search key
* @param maxEditDistance The maximum edit distance (Levenshtein)
* @return A Map of the matching keys to their value and edit distance
*/
SearchableMap.prototype.fuzzyGet = function (key, maxEditDistance) {
return fuzzySearch(this._tree, key, maxEditDistance);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
* @param key Key to get
* @return Value associated to the key, or `undefined` if the key is not
* found.
*/
SearchableMap.prototype.get = function (key) {
var node = lookup(this._tree, key);
return node !== undefined ? node.get(LEAF) : undefined;
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has
* @param key Key
* @return True if the key is in the map, false otherwise
*/
SearchableMap.prototype.has = function (key) {
var node = lookup(this._tree, key);
return node !== undefined && node.has(LEAF);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys
* @return An `Iterable` iterating through keys
*/
SearchableMap.prototype.keys = function () {
return new TreeIterator(this, KEYS);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set
* @param key Key to set
* @param value Value to associate to the key
* @return The [[SearchableMap]] itself, to allow chaining
*/
SearchableMap.prototype.set = function (key, value) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
node.set(LEAF, value);
return this;
};
Object.defineProperty(SearchableMap.prototype, "size", {
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size
*/
get: function () {
if (this._size) {
return this._size;
}
/** @ignore */
this._size = 0;
var iter = this.entries();
while (!iter.next().done)
this._size += 1;
return this._size;
},
enumerable: false,
configurable: true
});
/**
* Updates the value at the given key using the provided function. The function
* is called with the current value at the key, and its return value is used as
* the new value to be set.
*
* ### Example:
*
* ```javascript
* // Increment the current value by one
* searchableMap.update('somekey', (currentValue) => currentValue == null ? 0 : currentValue + 1)
* ```
*
* If the value at the given key is or will be an object, it might not require
* re-assignment. In that case it is better to use `fetch()`, because it is
* faster.
*
* @param key The key to update
* @param fn The function used to compute the new value from the current one
* @return The [[SearchableMap]] itself, to allow chaining
*/
SearchableMap.prototype.update = function (key, fn) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
node.set(LEAF, fn(node.get(LEAF)));
return this;
};
/**
* Fetches the value of the given key. If the value does not exist, calls the
* given function to create a new value, which is inserted at the given key
* and subsequently returned.
*
* ### Example:
*
* ```javascript
* const map = searchableMap.fetch('somekey', () => new Map())
* map.set('foo', 'bar')
* ```
*
* @param key The key to update
* @param defaultValue A function that creates a new value if the key does not exist
* @return The existing or new value at the given key
*/
SearchableMap.prototype.fetch = function (key, initial) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
var value = node.get(LEAF);
if (value === undefined) {
node.set(LEAF, value = initial());
}
return value;
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values
* @return An `Iterable` iterating through values.
*/
SearchableMap.prototype.values = function () {
return new TreeIterator(this, VALUES);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@iterator
*/
SearchableMap.prototype[Symbol.iterator] = function () {
return this.entries();
};
/**
* Creates a [[SearchableMap]] from an `Iterable` of entries
*
* @param entries Entries to be inserted in the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
SearchableMap.from = function (entries) {
var e_3, _a;
var tree = new SearchableMap();
try {
for (var entries_1 = __values(entries), entries_1_1 = entries_1.next(); !entries_1_1.done; entries_1_1 = entries_1.next()) {
var _b = __read(entries_1_1.value, 2), key = _b[0], value = _b[1];
tree.set(key, value);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (entries_1_1 && !entries_1_1.done && (_a = entries_1.return)) _a.call(entries_1);
}
finally { if (e_3) throw e_3.error; }
}
return tree;
};
/**
* Creates a [[SearchableMap]] from the iterable properties of a JavaScript object
*
* @param object Object of entries for the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
SearchableMap.fromObject = function (object) {
return SearchableMap.from(Object.entries(object));
};
return SearchableMap;
}());
var trackDown = function (tree, key, path) {
var e_4, _a;
if (path === void 0) { path = []; }
if (key.length === 0 || tree == null) {
return [tree, path];
}
try {
for (var _b = __values(tree.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
if (k !== LEAF && key.startsWith(k)) {
path.push([tree, k]); // performance: update in place
return trackDown(tree.get(k), key.slice(k.length), path);
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_4) throw e_4.error; }
}
path.push([tree, key]); // performance: update in place
return trackDown(undefined, '', path);
};
var lookup = function (tree, key) {
var e_5, _a;
if (key.length === 0 || tree == null) {
return tree;
}
try {
for (var _b = __values(tree.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
if (k !== LEAF && key.startsWith(k)) {
return lookup(tree.get(k), key.slice(k.length));
}
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_5) throw e_5.error; }
}
};
// Create a path in the radix tree for the given key, and returns the deepest
// node. This function is in the hot path for indexing. It avoids unnecessary
// string operations and recursion for performance.
var createPath = function (node, key) {
var e_6, _a;
var keyLength = key.length;
outer: for (var pos = 0; node && pos < keyLength;) {
try {
for (var _b = (e_6 = void 0, __values(node.keys())), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
// Check whether this key is a candidate: the first characters must match.
if (k !== LEAF && key[pos] === k[0]) {
var len = Math.min(keyLength - pos, k.length);
// Advance offset to the point where key and k no longer match.
var offset = 1;
while (offset < len && key[pos + offset] === k[offset])
++offset;
var child_1 = node.get(k);
if (offset === k.length) {
// The existing key is shorter than the key we need to create.
node = child_1;
}
else {
// Partial match: we need to insert an intermediate node to contain
// both the existing subtree and the new node.
var intermediate = new Map();
intermediate.set(k.slice(offset), child_1);
node.set(key.slice(pos, pos + offset), intermediate);
node.delete(k);
node = intermediate;
}
pos += offset;
continue outer;
}
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_6) throw e_6.error; }
}
// Create a final child node to contain the final suffix of the key.
var child = new Map();
node.set(key.slice(pos), child);
return child;
}
return node;
};
var remove = function (tree, key) {
var _a = __read(trackDown(tree, key), 2), node = _a[0], path = _a[1];
if (node === undefined) {
return;
}
node.delete(LEAF);
if (node.size === 0) {
cleanup(path);
}
else if (node.size === 1) {
var _b = __read(node.entries().next().value, 2), key_1 = _b[0], value = _b[1];
merge(path, key_1, value);
}
};
var cleanup = function (path) {
if (path.length === 0) {
return;
}
var _a = __read(last(path), 2), node = _a[0], key = _a[1];
node.delete(key);
if (node.size === 0) {
cleanup(path.slice(0, -1));
}
else if (node.size === 1) {
var _b = __read(node.entries().next().value, 2), key_2 = _b[0], value = _b[1];
if (key_2 !== LEAF) {
merge(path.slice(0, -1), key_2, value);
}
}
};
var merge = function (path, key, value) {
if (path.length === 0) {
return;
}
var _a = __read(last(path), 2), node = _a[0], nodeKey = _a[1];
node.set(nodeKey + key, value);
node.delete(nodeKey);
};
var last = function (array) {
return array[array.length - 1];
};
module.exports = SearchableMap;
//# sourceMappingURL=SearchableMap.cjs.map

File diff suppressed because one or more lines are too long

2450
node_modules/minisearch/dist/cjs/index.cjs generated vendored Normal file

File diff suppressed because it is too large Load diff

1
node_modules/minisearch/dist/cjs/index.cjs.map generated vendored Normal file

File diff suppressed because one or more lines are too long

678
node_modules/minisearch/dist/es/SearchableMap.js generated vendored Normal file
View file

@ -0,0 +1,678 @@
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
}
/** @ignore */
var ENTRIES = 'ENTRIES';
/** @ignore */
var KEYS = 'KEYS';
/** @ignore */
var VALUES = 'VALUES';
/** @ignore */
var LEAF = '';
/**
* @private
*/
var TreeIterator = /** @class */ (function () {
function TreeIterator(set, type) {
var node = set._tree;
var keys = Array.from(node.keys());
this.set = set;
this._type = type;
this._path = keys.length > 0 ? [{ node: node, keys: keys }] : [];
}
TreeIterator.prototype.next = function () {
var value = this.dive();
this.backtrack();
return value;
};
TreeIterator.prototype.dive = function () {
if (this._path.length === 0) {
return { done: true, value: undefined };
}
var _a = last$1(this._path), node = _a.node, keys = _a.keys;
if (last$1(keys) === LEAF) {
return { done: false, value: this.result() };
}
var child = node.get(last$1(keys));
this._path.push({ node: child, keys: Array.from(child.keys()) });
return this.dive();
};
TreeIterator.prototype.backtrack = function () {
if (this._path.length === 0) {
return;
}
var keys = last$1(this._path).keys;
keys.pop();
if (keys.length > 0) {
return;
}
this._path.pop();
this.backtrack();
};
TreeIterator.prototype.key = function () {
return this.set._prefix + this._path
.map(function (_a) {
var keys = _a.keys;
return last$1(keys);
})
.filter(function (key) { return key !== LEAF; })
.join('');
};
TreeIterator.prototype.value = function () {
return last$1(this._path).node.get(LEAF);
};
TreeIterator.prototype.result = function () {
switch (this._type) {
case VALUES: return this.value();
case KEYS: return this.key();
default: return [this.key(), this.value()];
}
};
TreeIterator.prototype[Symbol.iterator] = function () {
return this;
};
return TreeIterator;
}());
var last$1 = function (array) {
return array[array.length - 1];
};
/**
* @ignore
*/
var fuzzySearch = function (node, query, maxDistance) {
var results = new Map();
if (query === undefined)
return results;
// Number of columns in the Levenshtein matrix.
var n = query.length + 1;
// Matching terms can never be longer than N + maxDistance.
var m = n + maxDistance;
// Fill first matrix row and column with numbers: 0 1 2 3 ...
var matrix = new Uint8Array(m * n).fill(maxDistance + 1);
for (var j = 0; j < n; ++j)
matrix[j] = j;
for (var i = 1; i < m; ++i)
matrix[i * n] = i;
recurse(node, query, maxDistance, results, matrix, 1, n, '');
return results;
};
// Modified version of http://stevehanov.ca/blog/?id=114
// This builds a Levenshtein matrix for a given query and continuously updates
// it for nodes in the radix tree that fall within the given maximum edit
// distance. Keeping the same matrix around is beneficial especially for larger
// edit distances.
//
// k a t e <-- query
// 0 1 2 3 4
// c 1 1 2 3 4
// a 2 2 1 2 3
// t 3 3 2 1 [2] <-- edit distance
// ^
// ^ term in radix tree, rows are added and removed as needed
var recurse = function (node, query, maxDistance, results, matrix, m, n, prefix) {
var e_1, _a;
var offset = m * n;
try {
key: for (var _b = __values(node.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var key = _c.value;
if (key === LEAF) {
// We've reached a leaf node. Check if the edit distance acceptable and
// store the result if it is.
var distance = matrix[offset - 1];
if (distance <= maxDistance) {
results.set(prefix, [node.get(key), distance]);
}
}
else {
// Iterate over all characters in the key. Update the Levenshtein matrix
// and check if the minimum distance in the last row is still within the
// maximum edit distance. If it is, we can recurse over all child nodes.
var i = m;
for (var pos = 0; pos < key.length; ++pos, ++i) {
var char = key[pos];
var thisRowOffset = n * i;
var prevRowOffset = thisRowOffset - n;
// Set the first column based on the previous row, and initialize the
// minimum distance in the current row.
var minDistance = matrix[thisRowOffset];
var jmin = Math.max(0, i - maxDistance - 1);
var jmax = Math.min(n - 1, i + maxDistance);
// Iterate over remaining columns (characters in the query).
for (var j = jmin; j < jmax; ++j) {
var different = char !== query[j];
// It might make sense to only read the matrix positions used for
// deletion/insertion if the characters are different. But we want to
// avoid conditional reads for performance reasons.
var rpl = matrix[prevRowOffset + j] + +different;
var del = matrix[prevRowOffset + j + 1] + 1;
var ins = matrix[thisRowOffset + j] + 1;
var dist = matrix[thisRowOffset + j + 1] = Math.min(rpl, del, ins);
if (dist < minDistance)
minDistance = dist;
}
// Because distance will never decrease, we can stop. There will be no
// matching child nodes.
if (minDistance > maxDistance) {
continue key;
}
}
recurse(node.get(key), query, maxDistance, results, matrix, i, n, prefix + key);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
};
/**
* A class implementing the same interface as a standard JavaScript
* [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
* with string keys, but adding support for efficiently searching entries with
* prefix or fuzzy search. This class is used internally by [[MiniSearch]] as
* the inverted index data structure. The implementation is a radix tree
* (compressed prefix tree).
*
* Since this class can be of general utility beyond _MiniSearch_, it is
* exported by the `minisearch` package and can be imported (or required) as
* `minisearch/SearchableMap`.
*
* @typeParam T The type of the values stored in the map.
*/
var SearchableMap = /** @class */ (function () {
/**
* The constructor is normally called without arguments, creating an empty
* map. In order to create a [[SearchableMap]] from an iterable or from an
* object, check [[SearchableMap.from]] and [[SearchableMap.fromObject]].
*
* The constructor arguments are for internal use, when creating derived
* mutable views of a map at a prefix.
*/
function SearchableMap(tree, prefix) {
if (tree === void 0) { tree = new Map(); }
if (prefix === void 0) { prefix = ''; }
this._size = undefined;
this._tree = tree;
this._prefix = prefix;
}
/**
* Creates and returns a mutable view of this [[SearchableMap]], containing only
* entries that share the given prefix.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set("unicorn", 1)
* map.set("universe", 2)
* map.set("university", 3)
* map.set("unique", 4)
* map.set("hello", 5)
*
* let uni = map.atPrefix("uni")
* uni.get("unique") // => 4
* uni.get("unicorn") // => 1
* uni.get("hello") // => undefined
*
* let univer = map.atPrefix("univer")
* univer.get("unique") // => undefined
* univer.get("universe") // => 2
* univer.get("university") // => 3
* ```
*
* @param prefix The prefix
* @return A [[SearchableMap]] representing a mutable view of the original Map at the given prefix
*/
SearchableMap.prototype.atPrefix = function (prefix) {
var e_1, _a;
if (!prefix.startsWith(this._prefix)) {
throw new Error('Mismatched prefix');
}
var _b = __read(trackDown(this._tree, prefix.slice(this._prefix.length)), 2), node = _b[0], path = _b[1];
if (node === undefined) {
var _c = __read(last(path), 2), parentNode = _c[0], key = _c[1];
try {
for (var _d = __values(parentNode.keys()), _e = _d.next(); !_e.done; _e = _d.next()) {
var k = _e.value;
if (k !== LEAF && k.startsWith(key)) {
var node_1 = new Map();
node_1.set(k.slice(key.length), parentNode.get(k));
return new SearchableMap(node_1, prefix);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
}
finally { if (e_1) throw e_1.error; }
}
}
return new SearchableMap(node, prefix);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear
*/
SearchableMap.prototype.clear = function () {
this._size = undefined;
this._tree.clear();
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete
* @param key Key to delete
*/
SearchableMap.prototype.delete = function (key) {
this._size = undefined;
return remove(this._tree, key);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries
* @return An iterator iterating through `[key, value]` entries.
*/
SearchableMap.prototype.entries = function () {
return new TreeIterator(this, ENTRIES);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/forEach
* @param fn Iteration function
*/
SearchableMap.prototype.forEach = function (fn) {
var e_2, _a;
try {
for (var _b = __values(this), _c = _b.next(); !_c.done; _c = _b.next()) {
var _d = __read(_c.value, 2), key = _d[0], value = _d[1];
fn(key, value, this);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
};
/**
* Returns a Map of all the entries that have a key within the given edit
* distance from the search key. The keys of the returned Map are the matching
* keys, while the values are two-element arrays where the first element is
* the value associated to the key, and the second is the edit distance of the
* key to the search key.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set('hello', 'world')
* map.set('hell', 'yeah')
* map.set('ciao', 'mondo')
*
* // Get all entries that match the key 'hallo' with a maximum edit distance of 2
* map.fuzzyGet('hallo', 2)
* // => Map(2) { 'hello' => ['world', 1], 'hell' => ['yeah', 2] }
*
* // In the example, the "hello" key has value "world" and edit distance of 1
* // (change "e" to "a"), the key "hell" has value "yeah" and edit distance of 2
* // (change "e" to "a", delete "o")
* ```
*
* @param key The search key
* @param maxEditDistance The maximum edit distance (Levenshtein)
* @return A Map of the matching keys to their value and edit distance
*/
SearchableMap.prototype.fuzzyGet = function (key, maxEditDistance) {
return fuzzySearch(this._tree, key, maxEditDistance);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
* @param key Key to get
* @return Value associated to the key, or `undefined` if the key is not
* found.
*/
SearchableMap.prototype.get = function (key) {
var node = lookup(this._tree, key);
return node !== undefined ? node.get(LEAF) : undefined;
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has
* @param key Key
* @return True if the key is in the map, false otherwise
*/
SearchableMap.prototype.has = function (key) {
var node = lookup(this._tree, key);
return node !== undefined && node.has(LEAF);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys
* @return An `Iterable` iterating through keys
*/
SearchableMap.prototype.keys = function () {
return new TreeIterator(this, KEYS);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set
* @param key Key to set
* @param value Value to associate to the key
* @return The [[SearchableMap]] itself, to allow chaining
*/
SearchableMap.prototype.set = function (key, value) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
node.set(LEAF, value);
return this;
};
Object.defineProperty(SearchableMap.prototype, "size", {
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size
*/
get: function () {
if (this._size) {
return this._size;
}
/** @ignore */
this._size = 0;
var iter = this.entries();
while (!iter.next().done)
this._size += 1;
return this._size;
},
enumerable: false,
configurable: true
});
/**
* Updates the value at the given key using the provided function. The function
* is called with the current value at the key, and its return value is used as
* the new value to be set.
*
* ### Example:
*
* ```javascript
* // Increment the current value by one
* searchableMap.update('somekey', (currentValue) => currentValue == null ? 0 : currentValue + 1)
* ```
*
* If the value at the given key is or will be an object, it might not require
* re-assignment. In that case it is better to use `fetch()`, because it is
* faster.
*
* @param key The key to update
* @param fn The function used to compute the new value from the current one
* @return The [[SearchableMap]] itself, to allow chaining
*/
SearchableMap.prototype.update = function (key, fn) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
node.set(LEAF, fn(node.get(LEAF)));
return this;
};
/**
* Fetches the value of the given key. If the value does not exist, calls the
* given function to create a new value, which is inserted at the given key
* and subsequently returned.
*
* ### Example:
*
* ```javascript
* const map = searchableMap.fetch('somekey', () => new Map())
* map.set('foo', 'bar')
* ```
*
* @param key The key to update
* @param defaultValue A function that creates a new value if the key does not exist
* @return The existing or new value at the given key
*/
SearchableMap.prototype.fetch = function (key, initial) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
var value = node.get(LEAF);
if (value === undefined) {
node.set(LEAF, value = initial());
}
return value;
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values
* @return An `Iterable` iterating through values.
*/
SearchableMap.prototype.values = function () {
return new TreeIterator(this, VALUES);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@iterator
*/
SearchableMap.prototype[Symbol.iterator] = function () {
return this.entries();
};
/**
* Creates a [[SearchableMap]] from an `Iterable` of entries
*
* @param entries Entries to be inserted in the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
SearchableMap.from = function (entries) {
var e_3, _a;
var tree = new SearchableMap();
try {
for (var entries_1 = __values(entries), entries_1_1 = entries_1.next(); !entries_1_1.done; entries_1_1 = entries_1.next()) {
var _b = __read(entries_1_1.value, 2), key = _b[0], value = _b[1];
tree.set(key, value);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (entries_1_1 && !entries_1_1.done && (_a = entries_1.return)) _a.call(entries_1);
}
finally { if (e_3) throw e_3.error; }
}
return tree;
};
/**
* Creates a [[SearchableMap]] from the iterable properties of a JavaScript object
*
* @param object Object of entries for the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
SearchableMap.fromObject = function (object) {
return SearchableMap.from(Object.entries(object));
};
return SearchableMap;
}());
var trackDown = function (tree, key, path) {
var e_4, _a;
if (path === void 0) { path = []; }
if (key.length === 0 || tree == null) {
return [tree, path];
}
try {
for (var _b = __values(tree.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
if (k !== LEAF && key.startsWith(k)) {
path.push([tree, k]); // performance: update in place
return trackDown(tree.get(k), key.slice(k.length), path);
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_4) throw e_4.error; }
}
path.push([tree, key]); // performance: update in place
return trackDown(undefined, '', path);
};
var lookup = function (tree, key) {
var e_5, _a;
if (key.length === 0 || tree == null) {
return tree;
}
try {
for (var _b = __values(tree.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
if (k !== LEAF && key.startsWith(k)) {
return lookup(tree.get(k), key.slice(k.length));
}
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_5) throw e_5.error; }
}
};
// Create a path in the radix tree for the given key, and returns the deepest
// node. This function is in the hot path for indexing. It avoids unnecessary
// string operations and recursion for performance.
var createPath = function (node, key) {
var e_6, _a;
var keyLength = key.length;
outer: for (var pos = 0; node && pos < keyLength;) {
try {
for (var _b = (e_6 = void 0, __values(node.keys())), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
// Check whether this key is a candidate: the first characters must match.
if (k !== LEAF && key[pos] === k[0]) {
var len = Math.min(keyLength - pos, k.length);
// Advance offset to the point where key and k no longer match.
var offset = 1;
while (offset < len && key[pos + offset] === k[offset])
++offset;
var child_1 = node.get(k);
if (offset === k.length) {
// The existing key is shorter than the key we need to create.
node = child_1;
}
else {
// Partial match: we need to insert an intermediate node to contain
// both the existing subtree and the new node.
var intermediate = new Map();
intermediate.set(k.slice(offset), child_1);
node.set(key.slice(pos, pos + offset), intermediate);
node.delete(k);
node = intermediate;
}
pos += offset;
continue outer;
}
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_6) throw e_6.error; }
}
// Create a final child node to contain the final suffix of the key.
var child = new Map();
node.set(key.slice(pos), child);
return child;
}
return node;
};
var remove = function (tree, key) {
var _a = __read(trackDown(tree, key), 2), node = _a[0], path = _a[1];
if (node === undefined) {
return;
}
node.delete(LEAF);
if (node.size === 0) {
cleanup(path);
}
else if (node.size === 1) {
var _b = __read(node.entries().next().value, 2), key_1 = _b[0], value = _b[1];
merge(path, key_1, value);
}
};
var cleanup = function (path) {
if (path.length === 0) {
return;
}
var _a = __read(last(path), 2), node = _a[0], key = _a[1];
node.delete(key);
if (node.size === 0) {
cleanup(path.slice(0, -1));
}
else if (node.size === 1) {
var _b = __read(node.entries().next().value, 2), key_2 = _b[0], value = _b[1];
if (key_2 !== LEAF) {
merge(path.slice(0, -1), key_2, value);
}
}
};
var merge = function (path, key, value) {
if (path.length === 0) {
return;
}
var _a = __read(last(path), 2), node = _a[0], nodeKey = _a[1];
node.set(nodeKey + key, value);
node.delete(nodeKey);
};
var last = function (array) {
return array[array.length - 1];
};
export { SearchableMap as default };
//# sourceMappingURL=SearchableMap.js.map

1
node_modules/minisearch/dist/es/SearchableMap.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

2448
node_modules/minisearch/dist/es/index.js generated vendored Normal file

File diff suppressed because it is too large Load diff

1
node_modules/minisearch/dist/es/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

678
node_modules/minisearch/dist/es5m/SearchableMap.js generated vendored Normal file
View file

@ -0,0 +1,678 @@
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
}
/** @ignore */
var ENTRIES = 'ENTRIES';
/** @ignore */
var KEYS = 'KEYS';
/** @ignore */
var VALUES = 'VALUES';
/** @ignore */
var LEAF = '';
/**
* @private
*/
var TreeIterator = /** @class */ (function () {
function TreeIterator(set, type) {
var node = set._tree;
var keys = Array.from(node.keys());
this.set = set;
this._type = type;
this._path = keys.length > 0 ? [{ node: node, keys: keys }] : [];
}
TreeIterator.prototype.next = function () {
var value = this.dive();
this.backtrack();
return value;
};
TreeIterator.prototype.dive = function () {
if (this._path.length === 0) {
return { done: true, value: undefined };
}
var _a = last$1(this._path), node = _a.node, keys = _a.keys;
if (last$1(keys) === LEAF) {
return { done: false, value: this.result() };
}
var child = node.get(last$1(keys));
this._path.push({ node: child, keys: Array.from(child.keys()) });
return this.dive();
};
TreeIterator.prototype.backtrack = function () {
if (this._path.length === 0) {
return;
}
var keys = last$1(this._path).keys;
keys.pop();
if (keys.length > 0) {
return;
}
this._path.pop();
this.backtrack();
};
TreeIterator.prototype.key = function () {
return this.set._prefix + this._path
.map(function (_a) {
var keys = _a.keys;
return last$1(keys);
})
.filter(function (key) { return key !== LEAF; })
.join('');
};
TreeIterator.prototype.value = function () {
return last$1(this._path).node.get(LEAF);
};
TreeIterator.prototype.result = function () {
switch (this._type) {
case VALUES: return this.value();
case KEYS: return this.key();
default: return [this.key(), this.value()];
}
};
TreeIterator.prototype[Symbol.iterator] = function () {
return this;
};
return TreeIterator;
}());
var last$1 = function (array) {
return array[array.length - 1];
};
/**
* @ignore
*/
var fuzzySearch = function (node, query, maxDistance) {
var results = new Map();
if (query === undefined)
return results;
// Number of columns in the Levenshtein matrix.
var n = query.length + 1;
// Matching terms can never be longer than N + maxDistance.
var m = n + maxDistance;
// Fill first matrix row and column with numbers: 0 1 2 3 ...
var matrix = new Uint8Array(m * n).fill(maxDistance + 1);
for (var j = 0; j < n; ++j)
matrix[j] = j;
for (var i = 1; i < m; ++i)
matrix[i * n] = i;
recurse(node, query, maxDistance, results, matrix, 1, n, '');
return results;
};
// Modified version of http://stevehanov.ca/blog/?id=114
// This builds a Levenshtein matrix for a given query and continuously updates
// it for nodes in the radix tree that fall within the given maximum edit
// distance. Keeping the same matrix around is beneficial especially for larger
// edit distances.
//
// k a t e <-- query
// 0 1 2 3 4
// c 1 1 2 3 4
// a 2 2 1 2 3
// t 3 3 2 1 [2] <-- edit distance
// ^
// ^ term in radix tree, rows are added and removed as needed
var recurse = function (node, query, maxDistance, results, matrix, m, n, prefix) {
var e_1, _a;
var offset = m * n;
try {
key: for (var _b = __values(node.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var key = _c.value;
if (key === LEAF) {
// We've reached a leaf node. Check if the edit distance acceptable and
// store the result if it is.
var distance = matrix[offset - 1];
if (distance <= maxDistance) {
results.set(prefix, [node.get(key), distance]);
}
}
else {
// Iterate over all characters in the key. Update the Levenshtein matrix
// and check if the minimum distance in the last row is still within the
// maximum edit distance. If it is, we can recurse over all child nodes.
var i = m;
for (var pos = 0; pos < key.length; ++pos, ++i) {
var char = key[pos];
var thisRowOffset = n * i;
var prevRowOffset = thisRowOffset - n;
// Set the first column based on the previous row, and initialize the
// minimum distance in the current row.
var minDistance = matrix[thisRowOffset];
var jmin = Math.max(0, i - maxDistance - 1);
var jmax = Math.min(n - 1, i + maxDistance);
// Iterate over remaining columns (characters in the query).
for (var j = jmin; j < jmax; ++j) {
var different = char !== query[j];
// It might make sense to only read the matrix positions used for
// deletion/insertion if the characters are different. But we want to
// avoid conditional reads for performance reasons.
var rpl = matrix[prevRowOffset + j] + +different;
var del = matrix[prevRowOffset + j + 1] + 1;
var ins = matrix[thisRowOffset + j] + 1;
var dist = matrix[thisRowOffset + j + 1] = Math.min(rpl, del, ins);
if (dist < minDistance)
minDistance = dist;
}
// Because distance will never decrease, we can stop. There will be no
// matching child nodes.
if (minDistance > maxDistance) {
continue key;
}
}
recurse(node.get(key), query, maxDistance, results, matrix, i, n, prefix + key);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
};
/**
* A class implementing the same interface as a standard JavaScript
* [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
* with string keys, but adding support for efficiently searching entries with
* prefix or fuzzy search. This class is used internally by [[MiniSearch]] as
* the inverted index data structure. The implementation is a radix tree
* (compressed prefix tree).
*
* Since this class can be of general utility beyond _MiniSearch_, it is
* exported by the `minisearch` package and can be imported (or required) as
* `minisearch/SearchableMap`.
*
* @typeParam T The type of the values stored in the map.
*/
var SearchableMap = /** @class */ (function () {
/**
* The constructor is normally called without arguments, creating an empty
* map. In order to create a [[SearchableMap]] from an iterable or from an
* object, check [[SearchableMap.from]] and [[SearchableMap.fromObject]].
*
* The constructor arguments are for internal use, when creating derived
* mutable views of a map at a prefix.
*/
function SearchableMap(tree, prefix) {
if (tree === void 0) { tree = new Map(); }
if (prefix === void 0) { prefix = ''; }
this._size = undefined;
this._tree = tree;
this._prefix = prefix;
}
/**
* Creates and returns a mutable view of this [[SearchableMap]], containing only
* entries that share the given prefix.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set("unicorn", 1)
* map.set("universe", 2)
* map.set("university", 3)
* map.set("unique", 4)
* map.set("hello", 5)
*
* let uni = map.atPrefix("uni")
* uni.get("unique") // => 4
* uni.get("unicorn") // => 1
* uni.get("hello") // => undefined
*
* let univer = map.atPrefix("univer")
* univer.get("unique") // => undefined
* univer.get("universe") // => 2
* univer.get("university") // => 3
* ```
*
* @param prefix The prefix
* @return A [[SearchableMap]] representing a mutable view of the original Map at the given prefix
*/
SearchableMap.prototype.atPrefix = function (prefix) {
var e_1, _a;
if (!prefix.startsWith(this._prefix)) {
throw new Error('Mismatched prefix');
}
var _b = __read(trackDown(this._tree, prefix.slice(this._prefix.length)), 2), node = _b[0], path = _b[1];
if (node === undefined) {
var _c = __read(last(path), 2), parentNode = _c[0], key = _c[1];
try {
for (var _d = __values(parentNode.keys()), _e = _d.next(); !_e.done; _e = _d.next()) {
var k = _e.value;
if (k !== LEAF && k.startsWith(key)) {
var node_1 = new Map();
node_1.set(k.slice(key.length), parentNode.get(k));
return new SearchableMap(node_1, prefix);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
}
finally { if (e_1) throw e_1.error; }
}
}
return new SearchableMap(node, prefix);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear
*/
SearchableMap.prototype.clear = function () {
this._size = undefined;
this._tree.clear();
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete
* @param key Key to delete
*/
SearchableMap.prototype.delete = function (key) {
this._size = undefined;
return remove(this._tree, key);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries
* @return An iterator iterating through `[key, value]` entries.
*/
SearchableMap.prototype.entries = function () {
return new TreeIterator(this, ENTRIES);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/forEach
* @param fn Iteration function
*/
SearchableMap.prototype.forEach = function (fn) {
var e_2, _a;
try {
for (var _b = __values(this), _c = _b.next(); !_c.done; _c = _b.next()) {
var _d = __read(_c.value, 2), key = _d[0], value = _d[1];
fn(key, value, this);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
};
/**
* Returns a Map of all the entries that have a key within the given edit
* distance from the search key. The keys of the returned Map are the matching
* keys, while the values are two-element arrays where the first element is
* the value associated to the key, and the second is the edit distance of the
* key to the search key.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set('hello', 'world')
* map.set('hell', 'yeah')
* map.set('ciao', 'mondo')
*
* // Get all entries that match the key 'hallo' with a maximum edit distance of 2
* map.fuzzyGet('hallo', 2)
* // => Map(2) { 'hello' => ['world', 1], 'hell' => ['yeah', 2] }
*
* // In the example, the "hello" key has value "world" and edit distance of 1
* // (change "e" to "a"), the key "hell" has value "yeah" and edit distance of 2
* // (change "e" to "a", delete "o")
* ```
*
* @param key The search key
* @param maxEditDistance The maximum edit distance (Levenshtein)
* @return A Map of the matching keys to their value and edit distance
*/
SearchableMap.prototype.fuzzyGet = function (key, maxEditDistance) {
return fuzzySearch(this._tree, key, maxEditDistance);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
* @param key Key to get
* @return Value associated to the key, or `undefined` if the key is not
* found.
*/
SearchableMap.prototype.get = function (key) {
var node = lookup(this._tree, key);
return node !== undefined ? node.get(LEAF) : undefined;
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has
* @param key Key
* @return True if the key is in the map, false otherwise
*/
SearchableMap.prototype.has = function (key) {
var node = lookup(this._tree, key);
return node !== undefined && node.has(LEAF);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys
* @return An `Iterable` iterating through keys
*/
SearchableMap.prototype.keys = function () {
return new TreeIterator(this, KEYS);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set
* @param key Key to set
* @param value Value to associate to the key
* @return The [[SearchableMap]] itself, to allow chaining
*/
SearchableMap.prototype.set = function (key, value) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
node.set(LEAF, value);
return this;
};
Object.defineProperty(SearchableMap.prototype, "size", {
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size
*/
get: function () {
if (this._size) {
return this._size;
}
/** @ignore */
this._size = 0;
var iter = this.entries();
while (!iter.next().done)
this._size += 1;
return this._size;
},
enumerable: false,
configurable: true
});
/**
* Updates the value at the given key using the provided function. The function
* is called with the current value at the key, and its return value is used as
* the new value to be set.
*
* ### Example:
*
* ```javascript
* // Increment the current value by one
* searchableMap.update('somekey', (currentValue) => currentValue == null ? 0 : currentValue + 1)
* ```
*
* If the value at the given key is or will be an object, it might not require
* re-assignment. In that case it is better to use `fetch()`, because it is
* faster.
*
* @param key The key to update
* @param fn The function used to compute the new value from the current one
* @return The [[SearchableMap]] itself, to allow chaining
*/
SearchableMap.prototype.update = function (key, fn) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
node.set(LEAF, fn(node.get(LEAF)));
return this;
};
/**
* Fetches the value of the given key. If the value does not exist, calls the
* given function to create a new value, which is inserted at the given key
* and subsequently returned.
*
* ### Example:
*
* ```javascript
* const map = searchableMap.fetch('somekey', () => new Map())
* map.set('foo', 'bar')
* ```
*
* @param key The key to update
* @param defaultValue A function that creates a new value if the key does not exist
* @return The existing or new value at the given key
*/
SearchableMap.prototype.fetch = function (key, initial) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
var value = node.get(LEAF);
if (value === undefined) {
node.set(LEAF, value = initial());
}
return value;
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values
* @return An `Iterable` iterating through values.
*/
SearchableMap.prototype.values = function () {
return new TreeIterator(this, VALUES);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@iterator
*/
SearchableMap.prototype[Symbol.iterator] = function () {
return this.entries();
};
/**
* Creates a [[SearchableMap]] from an `Iterable` of entries
*
* @param entries Entries to be inserted in the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
SearchableMap.from = function (entries) {
var e_3, _a;
var tree = new SearchableMap();
try {
for (var entries_1 = __values(entries), entries_1_1 = entries_1.next(); !entries_1_1.done; entries_1_1 = entries_1.next()) {
var _b = __read(entries_1_1.value, 2), key = _b[0], value = _b[1];
tree.set(key, value);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (entries_1_1 && !entries_1_1.done && (_a = entries_1.return)) _a.call(entries_1);
}
finally { if (e_3) throw e_3.error; }
}
return tree;
};
/**
* Creates a [[SearchableMap]] from the iterable properties of a JavaScript object
*
* @param object Object of entries for the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
SearchableMap.fromObject = function (object) {
return SearchableMap.from(Object.entries(object));
};
return SearchableMap;
}());
var trackDown = function (tree, key, path) {
var e_4, _a;
if (path === void 0) { path = []; }
if (key.length === 0 || tree == null) {
return [tree, path];
}
try {
for (var _b = __values(tree.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
if (k !== LEAF && key.startsWith(k)) {
path.push([tree, k]); // performance: update in place
return trackDown(tree.get(k), key.slice(k.length), path);
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_4) throw e_4.error; }
}
path.push([tree, key]); // performance: update in place
return trackDown(undefined, '', path);
};
var lookup = function (tree, key) {
var e_5, _a;
if (key.length === 0 || tree == null) {
return tree;
}
try {
for (var _b = __values(tree.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
if (k !== LEAF && key.startsWith(k)) {
return lookup(tree.get(k), key.slice(k.length));
}
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_5) throw e_5.error; }
}
};
// Create a path in the radix tree for the given key, and returns the deepest
// node. This function is in the hot path for indexing. It avoids unnecessary
// string operations and recursion for performance.
var createPath = function (node, key) {
var e_6, _a;
var keyLength = key.length;
outer: for (var pos = 0; node && pos < keyLength;) {
try {
for (var _b = (e_6 = void 0, __values(node.keys())), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
// Check whether this key is a candidate: the first characters must match.
if (k !== LEAF && key[pos] === k[0]) {
var len = Math.min(keyLength - pos, k.length);
// Advance offset to the point where key and k no longer match.
var offset = 1;
while (offset < len && key[pos + offset] === k[offset])
++offset;
var child_1 = node.get(k);
if (offset === k.length) {
// The existing key is shorter than the key we need to create.
node = child_1;
}
else {
// Partial match: we need to insert an intermediate node to contain
// both the existing subtree and the new node.
var intermediate = new Map();
intermediate.set(k.slice(offset), child_1);
node.set(key.slice(pos, pos + offset), intermediate);
node.delete(k);
node = intermediate;
}
pos += offset;
continue outer;
}
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_6) throw e_6.error; }
}
// Create a final child node to contain the final suffix of the key.
var child = new Map();
node.set(key.slice(pos), child);
return child;
}
return node;
};
var remove = function (tree, key) {
var _a = __read(trackDown(tree, key), 2), node = _a[0], path = _a[1];
if (node === undefined) {
return;
}
node.delete(LEAF);
if (node.size === 0) {
cleanup(path);
}
else if (node.size === 1) {
var _b = __read(node.entries().next().value, 2), key_1 = _b[0], value = _b[1];
merge(path, key_1, value);
}
};
var cleanup = function (path) {
if (path.length === 0) {
return;
}
var _a = __read(last(path), 2), node = _a[0], key = _a[1];
node.delete(key);
if (node.size === 0) {
cleanup(path.slice(0, -1));
}
else if (node.size === 1) {
var _b = __read(node.entries().next().value, 2), key_2 = _b[0], value = _b[1];
if (key_2 !== LEAF) {
merge(path.slice(0, -1), key_2, value);
}
}
};
var merge = function (path, key, value) {
if (path.length === 0) {
return;
}
var _a = __read(last(path), 2), node = _a[0], nodeKey = _a[1];
node.set(nodeKey + key, value);
node.delete(nodeKey);
};
var last = function (array) {
return array[array.length - 1];
};
export { SearchableMap as default };
//# sourceMappingURL=SearchableMap.js.map

File diff suppressed because one or more lines are too long

2448
node_modules/minisearch/dist/es5m/index.js generated vendored Normal file

File diff suppressed because it is too large Load diff

1
node_modules/minisearch/dist/es5m/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

251
node_modules/minisearch/dist/types/SearchableMap.d.ts generated vendored Normal file
View file

@ -0,0 +1,251 @@
type LeafType = '' & {
readonly __tag: unique symbol;
};
interface RadixTree<T> extends Map<string, T | RadixTree<T>> {
get(key: LeafType): T | undefined;
get(key: string): RadixTree<T> | undefined;
set(key: LeafType, value: T): this;
set(key: string, value: RadixTree<T>): this;
}
type Entry<T> = [string, T];
interface Iterators<T> {
ENTRIES: Entry<T>;
KEYS: string;
VALUES: T;
}
type Kind<T> = keyof Iterators<T>;
type Result<T, K extends keyof Iterators<T>> = Iterators<T>[K];
type IteratorPath<T> = {
node: RadixTree<T>;
keys: string[];
}[];
type IterableSet<T> = {
_tree: RadixTree<T>;
_prefix: string;
};
/**
* @private
*/
declare class TreeIterator<T, K extends Kind<T>> implements Iterator<Result<T, K>> {
set: IterableSet<T>;
_type: K;
_path: IteratorPath<T>;
constructor(set: IterableSet<T>, type: K);
next(): IteratorResult<Result<T, K>>;
dive(): IteratorResult<Result<T, K>>;
backtrack(): void;
key(): string;
value(): T;
result(): Result<T, K>;
[Symbol.iterator](): this;
}
type FuzzyResult<T> = [T, number];
type FuzzyResults<T> = Map<string, FuzzyResult<T>>;
/**
* A class implementing the same interface as a standard JavaScript
* [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
* with string keys, but adding support for efficiently searching entries with
* prefix or fuzzy search. This class is used internally by [[MiniSearch]] as
* the inverted index data structure. The implementation is a radix tree
* (compressed prefix tree).
*
* Since this class can be of general utility beyond _MiniSearch_, it is
* exported by the `minisearch` package and can be imported (or required) as
* `minisearch/SearchableMap`.
*
* @typeParam T The type of the values stored in the map.
*/
declare class SearchableMap<T = any> {
/**
* @internal
*/
_tree: RadixTree<T>;
/**
* @internal
*/
_prefix: string;
private _size;
/**
* The constructor is normally called without arguments, creating an empty
* map. In order to create a [[SearchableMap]] from an iterable or from an
* object, check [[SearchableMap.from]] and [[SearchableMap.fromObject]].
*
* The constructor arguments are for internal use, when creating derived
* mutable views of a map at a prefix.
*/
constructor(tree?: RadixTree<T>, prefix?: string);
/**
* Creates and returns a mutable view of this [[SearchableMap]], containing only
* entries that share the given prefix.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set("unicorn", 1)
* map.set("universe", 2)
* map.set("university", 3)
* map.set("unique", 4)
* map.set("hello", 5)
*
* let uni = map.atPrefix("uni")
* uni.get("unique") // => 4
* uni.get("unicorn") // => 1
* uni.get("hello") // => undefined
*
* let univer = map.atPrefix("univer")
* univer.get("unique") // => undefined
* univer.get("universe") // => 2
* univer.get("university") // => 3
* ```
*
* @param prefix The prefix
* @return A [[SearchableMap]] representing a mutable view of the original Map at the given prefix
*/
atPrefix(prefix: string): SearchableMap<T>;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear
*/
clear(): void;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete
* @param key Key to delete
*/
delete(key: string): void;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries
* @return An iterator iterating through `[key, value]` entries.
*/
entries(): TreeIterator<T, "ENTRIES">;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/forEach
* @param fn Iteration function
*/
forEach(fn: (key: string, value: T, map: SearchableMap) => void): void;
/**
* Returns a Map of all the entries that have a key within the given edit
* distance from the search key. The keys of the returned Map are the matching
* keys, while the values are two-element arrays where the first element is
* the value associated to the key, and the second is the edit distance of the
* key to the search key.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set('hello', 'world')
* map.set('hell', 'yeah')
* map.set('ciao', 'mondo')
*
* // Get all entries that match the key 'hallo' with a maximum edit distance of 2
* map.fuzzyGet('hallo', 2)
* // => Map(2) { 'hello' => ['world', 1], 'hell' => ['yeah', 2] }
*
* // In the example, the "hello" key has value "world" and edit distance of 1
* // (change "e" to "a"), the key "hell" has value "yeah" and edit distance of 2
* // (change "e" to "a", delete "o")
* ```
*
* @param key The search key
* @param maxEditDistance The maximum edit distance (Levenshtein)
* @return A Map of the matching keys to their value and edit distance
*/
fuzzyGet(key: string, maxEditDistance: number): FuzzyResults<T>;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
* @param key Key to get
* @return Value associated to the key, or `undefined` if the key is not
* found.
*/
get(key: string): T | undefined;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has
* @param key Key
* @return True if the key is in the map, false otherwise
*/
has(key: string): boolean;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys
* @return An `Iterable` iterating through keys
*/
keys(): TreeIterator<T, "KEYS">;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set
* @param key Key to set
* @param value Value to associate to the key
* @return The [[SearchableMap]] itself, to allow chaining
*/
set(key: string, value: T): SearchableMap<T>;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size
*/
get size(): number;
/**
* Updates the value at the given key using the provided function. The function
* is called with the current value at the key, and its return value is used as
* the new value to be set.
*
* ### Example:
*
* ```javascript
* // Increment the current value by one
* searchableMap.update('somekey', (currentValue) => currentValue == null ? 0 : currentValue + 1)
* ```
*
* If the value at the given key is or will be an object, it might not require
* re-assignment. In that case it is better to use `fetch()`, because it is
* faster.
*
* @param key The key to update
* @param fn The function used to compute the new value from the current one
* @return The [[SearchableMap]] itself, to allow chaining
*/
update(key: string, fn: (value: T | undefined) => T): SearchableMap<T>;
/**
* Fetches the value of the given key. If the value does not exist, calls the
* given function to create a new value, which is inserted at the given key
* and subsequently returned.
*
* ### Example:
*
* ```javascript
* const map = searchableMap.fetch('somekey', () => new Map())
* map.set('foo', 'bar')
* ```
*
* @param key The key to update
* @param defaultValue A function that creates a new value if the key does not exist
* @return The existing or new value at the given key
*/
fetch(key: string, initial: () => T): T;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values
* @return An `Iterable` iterating through values.
*/
values(): TreeIterator<T, "VALUES">;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@iterator
*/
[Symbol.iterator](): TreeIterator<T, "ENTRIES">;
/**
* Creates a [[SearchableMap]] from an `Iterable` of entries
*
* @param entries Entries to be inserted in the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
static from<T = any>(entries: Iterable<Entry<T>> | Entry<T>[]): SearchableMap<any>;
/**
* Creates a [[SearchableMap]] from the iterable properties of a JavaScript object
*
* @param object Object of entries for the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
static fromObject<T = any>(object: {
[key: string]: T;
}): SearchableMap<any>;
}
export { SearchableMap as default };

1298
node_modules/minisearch/dist/types/index.d.ts generated vendored Normal file

File diff suppressed because it is too large Load diff

686
node_modules/minisearch/dist/umd/SearchableMap.js generated vendored Normal file
View file

@ -0,0 +1,686 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.MiniSearch = factory());
})(this, (function () { 'use strict';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
}
/** @ignore */
var ENTRIES = 'ENTRIES';
/** @ignore */
var KEYS = 'KEYS';
/** @ignore */
var VALUES = 'VALUES';
/** @ignore */
var LEAF = '';
/**
* @private
*/
var TreeIterator = /** @class */ (function () {
function TreeIterator(set, type) {
var node = set._tree;
var keys = Array.from(node.keys());
this.set = set;
this._type = type;
this._path = keys.length > 0 ? [{ node: node, keys: keys }] : [];
}
TreeIterator.prototype.next = function () {
var value = this.dive();
this.backtrack();
return value;
};
TreeIterator.prototype.dive = function () {
if (this._path.length === 0) {
return { done: true, value: undefined };
}
var _a = last$1(this._path), node = _a.node, keys = _a.keys;
if (last$1(keys) === LEAF) {
return { done: false, value: this.result() };
}
var child = node.get(last$1(keys));
this._path.push({ node: child, keys: Array.from(child.keys()) });
return this.dive();
};
TreeIterator.prototype.backtrack = function () {
if (this._path.length === 0) {
return;
}
var keys = last$1(this._path).keys;
keys.pop();
if (keys.length > 0) {
return;
}
this._path.pop();
this.backtrack();
};
TreeIterator.prototype.key = function () {
return this.set._prefix + this._path
.map(function (_a) {
var keys = _a.keys;
return last$1(keys);
})
.filter(function (key) { return key !== LEAF; })
.join('');
};
TreeIterator.prototype.value = function () {
return last$1(this._path).node.get(LEAF);
};
TreeIterator.prototype.result = function () {
switch (this._type) {
case VALUES: return this.value();
case KEYS: return this.key();
default: return [this.key(), this.value()];
}
};
TreeIterator.prototype[Symbol.iterator] = function () {
return this;
};
return TreeIterator;
}());
var last$1 = function (array) {
return array[array.length - 1];
};
/**
* @ignore
*/
var fuzzySearch = function (node, query, maxDistance) {
var results = new Map();
if (query === undefined)
return results;
// Number of columns in the Levenshtein matrix.
var n = query.length + 1;
// Matching terms can never be longer than N + maxDistance.
var m = n + maxDistance;
// Fill first matrix row and column with numbers: 0 1 2 3 ...
var matrix = new Uint8Array(m * n).fill(maxDistance + 1);
for (var j = 0; j < n; ++j)
matrix[j] = j;
for (var i = 1; i < m; ++i)
matrix[i * n] = i;
recurse(node, query, maxDistance, results, matrix, 1, n, '');
return results;
};
// Modified version of http://stevehanov.ca/blog/?id=114
// This builds a Levenshtein matrix for a given query and continuously updates
// it for nodes in the radix tree that fall within the given maximum edit
// distance. Keeping the same matrix around is beneficial especially for larger
// edit distances.
//
// k a t e <-- query
// 0 1 2 3 4
// c 1 1 2 3 4
// a 2 2 1 2 3
// t 3 3 2 1 [2] <-- edit distance
// ^
// ^ term in radix tree, rows are added and removed as needed
var recurse = function (node, query, maxDistance, results, matrix, m, n, prefix) {
var e_1, _a;
var offset = m * n;
try {
key: for (var _b = __values(node.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var key = _c.value;
if (key === LEAF) {
// We've reached a leaf node. Check if the edit distance acceptable and
// store the result if it is.
var distance = matrix[offset - 1];
if (distance <= maxDistance) {
results.set(prefix, [node.get(key), distance]);
}
}
else {
// Iterate over all characters in the key. Update the Levenshtein matrix
// and check if the minimum distance in the last row is still within the
// maximum edit distance. If it is, we can recurse over all child nodes.
var i = m;
for (var pos = 0; pos < key.length; ++pos, ++i) {
var char = key[pos];
var thisRowOffset = n * i;
var prevRowOffset = thisRowOffset - n;
// Set the first column based on the previous row, and initialize the
// minimum distance in the current row.
var minDistance = matrix[thisRowOffset];
var jmin = Math.max(0, i - maxDistance - 1);
var jmax = Math.min(n - 1, i + maxDistance);
// Iterate over remaining columns (characters in the query).
for (var j = jmin; j < jmax; ++j) {
var different = char !== query[j];
// It might make sense to only read the matrix positions used for
// deletion/insertion if the characters are different. But we want to
// avoid conditional reads for performance reasons.
var rpl = matrix[prevRowOffset + j] + +different;
var del = matrix[prevRowOffset + j + 1] + 1;
var ins = matrix[thisRowOffset + j] + 1;
var dist = matrix[thisRowOffset + j + 1] = Math.min(rpl, del, ins);
if (dist < minDistance)
minDistance = dist;
}
// Because distance will never decrease, we can stop. There will be no
// matching child nodes.
if (minDistance > maxDistance) {
continue key;
}
}
recurse(node.get(key), query, maxDistance, results, matrix, i, n, prefix + key);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
};
/**
* A class implementing the same interface as a standard JavaScript
* [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
* with string keys, but adding support for efficiently searching entries with
* prefix or fuzzy search. This class is used internally by [[MiniSearch]] as
* the inverted index data structure. The implementation is a radix tree
* (compressed prefix tree).
*
* Since this class can be of general utility beyond _MiniSearch_, it is
* exported by the `minisearch` package and can be imported (or required) as
* `minisearch/SearchableMap`.
*
* @typeParam T The type of the values stored in the map.
*/
var SearchableMap = /** @class */ (function () {
/**
* The constructor is normally called without arguments, creating an empty
* map. In order to create a [[SearchableMap]] from an iterable or from an
* object, check [[SearchableMap.from]] and [[SearchableMap.fromObject]].
*
* The constructor arguments are for internal use, when creating derived
* mutable views of a map at a prefix.
*/
function SearchableMap(tree, prefix) {
if (tree === void 0) { tree = new Map(); }
if (prefix === void 0) { prefix = ''; }
this._size = undefined;
this._tree = tree;
this._prefix = prefix;
}
/**
* Creates and returns a mutable view of this [[SearchableMap]], containing only
* entries that share the given prefix.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set("unicorn", 1)
* map.set("universe", 2)
* map.set("university", 3)
* map.set("unique", 4)
* map.set("hello", 5)
*
* let uni = map.atPrefix("uni")
* uni.get("unique") // => 4
* uni.get("unicorn") // => 1
* uni.get("hello") // => undefined
*
* let univer = map.atPrefix("univer")
* univer.get("unique") // => undefined
* univer.get("universe") // => 2
* univer.get("university") // => 3
* ```
*
* @param prefix The prefix
* @return A [[SearchableMap]] representing a mutable view of the original Map at the given prefix
*/
SearchableMap.prototype.atPrefix = function (prefix) {
var e_1, _a;
if (!prefix.startsWith(this._prefix)) {
throw new Error('Mismatched prefix');
}
var _b = __read(trackDown(this._tree, prefix.slice(this._prefix.length)), 2), node = _b[0], path = _b[1];
if (node === undefined) {
var _c = __read(last(path), 2), parentNode = _c[0], key = _c[1];
try {
for (var _d = __values(parentNode.keys()), _e = _d.next(); !_e.done; _e = _d.next()) {
var k = _e.value;
if (k !== LEAF && k.startsWith(key)) {
var node_1 = new Map();
node_1.set(k.slice(key.length), parentNode.get(k));
return new SearchableMap(node_1, prefix);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
}
finally { if (e_1) throw e_1.error; }
}
}
return new SearchableMap(node, prefix);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear
*/
SearchableMap.prototype.clear = function () {
this._size = undefined;
this._tree.clear();
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete
* @param key Key to delete
*/
SearchableMap.prototype.delete = function (key) {
this._size = undefined;
return remove(this._tree, key);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries
* @return An iterator iterating through `[key, value]` entries.
*/
SearchableMap.prototype.entries = function () {
return new TreeIterator(this, ENTRIES);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/forEach
* @param fn Iteration function
*/
SearchableMap.prototype.forEach = function (fn) {
var e_2, _a;
try {
for (var _b = __values(this), _c = _b.next(); !_c.done; _c = _b.next()) {
var _d = __read(_c.value, 2), key = _d[0], value = _d[1];
fn(key, value, this);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
};
/**
* Returns a Map of all the entries that have a key within the given edit
* distance from the search key. The keys of the returned Map are the matching
* keys, while the values are two-element arrays where the first element is
* the value associated to the key, and the second is the edit distance of the
* key to the search key.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set('hello', 'world')
* map.set('hell', 'yeah')
* map.set('ciao', 'mondo')
*
* // Get all entries that match the key 'hallo' with a maximum edit distance of 2
* map.fuzzyGet('hallo', 2)
* // => Map(2) { 'hello' => ['world', 1], 'hell' => ['yeah', 2] }
*
* // In the example, the "hello" key has value "world" and edit distance of 1
* // (change "e" to "a"), the key "hell" has value "yeah" and edit distance of 2
* // (change "e" to "a", delete "o")
* ```
*
* @param key The search key
* @param maxEditDistance The maximum edit distance (Levenshtein)
* @return A Map of the matching keys to their value and edit distance
*/
SearchableMap.prototype.fuzzyGet = function (key, maxEditDistance) {
return fuzzySearch(this._tree, key, maxEditDistance);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
* @param key Key to get
* @return Value associated to the key, or `undefined` if the key is not
* found.
*/
SearchableMap.prototype.get = function (key) {
var node = lookup(this._tree, key);
return node !== undefined ? node.get(LEAF) : undefined;
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has
* @param key Key
* @return True if the key is in the map, false otherwise
*/
SearchableMap.prototype.has = function (key) {
var node = lookup(this._tree, key);
return node !== undefined && node.has(LEAF);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys
* @return An `Iterable` iterating through keys
*/
SearchableMap.prototype.keys = function () {
return new TreeIterator(this, KEYS);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set
* @param key Key to set
* @param value Value to associate to the key
* @return The [[SearchableMap]] itself, to allow chaining
*/
SearchableMap.prototype.set = function (key, value) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
node.set(LEAF, value);
return this;
};
Object.defineProperty(SearchableMap.prototype, "size", {
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size
*/
get: function () {
if (this._size) {
return this._size;
}
/** @ignore */
this._size = 0;
var iter = this.entries();
while (!iter.next().done)
this._size += 1;
return this._size;
},
enumerable: false,
configurable: true
});
/**
* Updates the value at the given key using the provided function. The function
* is called with the current value at the key, and its return value is used as
* the new value to be set.
*
* ### Example:
*
* ```javascript
* // Increment the current value by one
* searchableMap.update('somekey', (currentValue) => currentValue == null ? 0 : currentValue + 1)
* ```
*
* If the value at the given key is or will be an object, it might not require
* re-assignment. In that case it is better to use `fetch()`, because it is
* faster.
*
* @param key The key to update
* @param fn The function used to compute the new value from the current one
* @return The [[SearchableMap]] itself, to allow chaining
*/
SearchableMap.prototype.update = function (key, fn) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
node.set(LEAF, fn(node.get(LEAF)));
return this;
};
/**
* Fetches the value of the given key. If the value does not exist, calls the
* given function to create a new value, which is inserted at the given key
* and subsequently returned.
*
* ### Example:
*
* ```javascript
* const map = searchableMap.fetch('somekey', () => new Map())
* map.set('foo', 'bar')
* ```
*
* @param key The key to update
* @param defaultValue A function that creates a new value if the key does not exist
* @return The existing or new value at the given key
*/
SearchableMap.prototype.fetch = function (key, initial) {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
this._size = undefined;
var node = createPath(this._tree, key);
var value = node.get(LEAF);
if (value === undefined) {
node.set(LEAF, value = initial());
}
return value;
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values
* @return An `Iterable` iterating through values.
*/
SearchableMap.prototype.values = function () {
return new TreeIterator(this, VALUES);
};
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@iterator
*/
SearchableMap.prototype[Symbol.iterator] = function () {
return this.entries();
};
/**
* Creates a [[SearchableMap]] from an `Iterable` of entries
*
* @param entries Entries to be inserted in the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
SearchableMap.from = function (entries) {
var e_3, _a;
var tree = new SearchableMap();
try {
for (var entries_1 = __values(entries), entries_1_1 = entries_1.next(); !entries_1_1.done; entries_1_1 = entries_1.next()) {
var _b = __read(entries_1_1.value, 2), key = _b[0], value = _b[1];
tree.set(key, value);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (entries_1_1 && !entries_1_1.done && (_a = entries_1.return)) _a.call(entries_1);
}
finally { if (e_3) throw e_3.error; }
}
return tree;
};
/**
* Creates a [[SearchableMap]] from the iterable properties of a JavaScript object
*
* @param object Object of entries for the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
SearchableMap.fromObject = function (object) {
return SearchableMap.from(Object.entries(object));
};
return SearchableMap;
}());
var trackDown = function (tree, key, path) {
var e_4, _a;
if (path === void 0) { path = []; }
if (key.length === 0 || tree == null) {
return [tree, path];
}
try {
for (var _b = __values(tree.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
if (k !== LEAF && key.startsWith(k)) {
path.push([tree, k]); // performance: update in place
return trackDown(tree.get(k), key.slice(k.length), path);
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_4) throw e_4.error; }
}
path.push([tree, key]); // performance: update in place
return trackDown(undefined, '', path);
};
var lookup = function (tree, key) {
var e_5, _a;
if (key.length === 0 || tree == null) {
return tree;
}
try {
for (var _b = __values(tree.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
if (k !== LEAF && key.startsWith(k)) {
return lookup(tree.get(k), key.slice(k.length));
}
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_5) throw e_5.error; }
}
};
// Create a path in the radix tree for the given key, and returns the deepest
// node. This function is in the hot path for indexing. It avoids unnecessary
// string operations and recursion for performance.
var createPath = function (node, key) {
var e_6, _a;
var keyLength = key.length;
outer: for (var pos = 0; node && pos < keyLength;) {
try {
for (var _b = (e_6 = void 0, __values(node.keys())), _c = _b.next(); !_c.done; _c = _b.next()) {
var k = _c.value;
// Check whether this key is a candidate: the first characters must match.
if (k !== LEAF && key[pos] === k[0]) {
var len = Math.min(keyLength - pos, k.length);
// Advance offset to the point where key and k no longer match.
var offset = 1;
while (offset < len && key[pos + offset] === k[offset])
++offset;
var child_1 = node.get(k);
if (offset === k.length) {
// The existing key is shorter than the key we need to create.
node = child_1;
}
else {
// Partial match: we need to insert an intermediate node to contain
// both the existing subtree and the new node.
var intermediate = new Map();
intermediate.set(k.slice(offset), child_1);
node.set(key.slice(pos, pos + offset), intermediate);
node.delete(k);
node = intermediate;
}
pos += offset;
continue outer;
}
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_6) throw e_6.error; }
}
// Create a final child node to contain the final suffix of the key.
var child = new Map();
node.set(key.slice(pos), child);
return child;
}
return node;
};
var remove = function (tree, key) {
var _a = __read(trackDown(tree, key), 2), node = _a[0], path = _a[1];
if (node === undefined) {
return;
}
node.delete(LEAF);
if (node.size === 0) {
cleanup(path);
}
else if (node.size === 1) {
var _b = __read(node.entries().next().value, 2), key_1 = _b[0], value = _b[1];
merge(path, key_1, value);
}
};
var cleanup = function (path) {
if (path.length === 0) {
return;
}
var _a = __read(last(path), 2), node = _a[0], key = _a[1];
node.delete(key);
if (node.size === 0) {
cleanup(path.slice(0, -1));
}
else if (node.size === 1) {
var _b = __read(node.entries().next().value, 2), key_2 = _b[0], value = _b[1];
if (key_2 !== LEAF) {
merge(path.slice(0, -1), key_2, value);
}
}
};
var merge = function (path, key, value) {
if (path.length === 0) {
return;
}
var _a = __read(last(path), 2), node = _a[0], nodeKey = _a[1];
node.set(nodeKey + key, value);
node.delete(nodeKey);
};
var last = function (array) {
return array[array.length - 1];
};
return SearchableMap;
}));
//# sourceMappingURL=SearchableMap.js.map

File diff suppressed because one or more lines are too long

2456
node_modules/minisearch/dist/umd/index.js generated vendored Normal file

File diff suppressed because it is too large Load diff

1
node_modules/minisearch/dist/umd/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

104
node_modules/minisearch/package.json generated vendored Normal file
View file

@ -0,0 +1,104 @@
{
"name": "minisearch",
"version": "6.1.0",
"description": "Tiny but powerful full-text search engine for browser and Node",
"main": "dist/umd/index.js",
"module": "dist/es5m/index.js",
"es2015": "dist/es/index.js",
"type": "module",
"exports": {
".": {
"types": "./dist/types/index.d.ts",
"require": "./dist/cjs/index.cjs",
"default": "./dist/es/index.js"
},
"./SearchableMap": {
"types": "./dist/types/SearchableMap.d.ts",
"require": "./dist/cjs/SearchableMap.cjs",
"default": "./dist/es/SearchableMap.js"
}
},
"unpkg": "./dist/umd/index.js",
"jsdelivr": "./dist/umd/index.js",
"types": "./dist/types/index.d.ts",
"author": "Luca Ongaro",
"homepage": "https://lucaong.github.io/minisearch/",
"bugs": "https://github.com/lucaong/minisearch/issues",
"repository": {
"type": "git",
"url": "https://github.com/lucaong/minisearch.git"
},
"keywords": [
"search",
"full text",
"fuzzy",
"prefix",
"auto suggest",
"auto complete",
"index"
],
"license": "MIT",
"dependencies": {},
"devDependencies": {
"@rollup/plugin-terser": "^0.3.0",
"@rollup/plugin-typescript": "^11.0.0",
"@types/benchmark": "^2.1.1",
"@typescript-eslint/eslint-plugin": "^5.26.0",
"@typescript-eslint/parser": "^5.26.0",
"benchmark": "^2.1.4",
"core-js": "^3.1.4",
"coveralls": "^3.0.2",
"eslint": "^8.16.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-n": "^15.2.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"fast-check": "^3.0.0",
"jest": "^29.3.1",
"regenerator-runtime": "^0.13.1",
"rollup": "^3.4.0",
"rollup-plugin-dts": "^5.0.0",
"snazzy": "^9.0.0",
"ts-jest": "^29.0.3",
"tslib": "^2.0.1",
"typedoc": "^0.19.1",
"typescript": "^4.0.2"
},
"files": [
"/dist/**/*",
"/src/**/*"
],
"jest": {
"testEnvironmentOptions": {
"url": "http://localhost:3000/"
},
"transform": {
"\\.(js|ts)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js"
],
"testRegex": "\\.test\\.(ts|js)$",
"setupFilesAfterEnv": [
"<rootDir>/src/testSetup/jest.js"
]
},
"scripts": {
"test": "jest",
"test-watch": "jest --watch",
"coverage": "jest --coverage",
"benchmark": "yarn build-benchmark && NODE_ENV=production node --expose-gc benchmarks/dist/index.cjs",
"build-benchmark": "BENCHMARKS=true yarn build",
"build": "yarn clean-build && NODE_ENV=production rollup -c",
"clean-build": "rm -rf dist",
"build-minified": "MINIFY=true yarn build",
"build-docs": "typedoc --options typedoc.json && touch docs/.nojekyll && yarn build-examples",
"build-examples": "yarn build && cd examples && yarn install && yarn build && cd ../",
"lint": "eslint 'src/**/*.{js,ts}'",
"lintfix": "eslint --fix 'src/**/*.{js,ts}'",
"prepublishOnly": "yarn test && yarn build"
},
"sideEffects": false
}

1833
node_modules/minisearch/src/MiniSearch.test.js generated vendored Normal file

File diff suppressed because it is too large Load diff

1952
node_modules/minisearch/src/MiniSearch.ts generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,314 @@
/* eslint-env jest */
import SearchableMap from './SearchableMap'
import * as fc from 'fast-check'
describe('SearchableMap', () => {
const strings = ['bin', 'border', 'acqua', 'aqua', 'poisson', 'parachute',
'parapendio', 'acquamarina', 'summertime', 'summer', 'join', 'mediterraneo',
'perciò', 'borderline', 'bo']
const keyValues = strings.map((key, i) => [key, i])
const object = keyValues.reduce((obj, [key, value]) => ({ ...obj, [key]: value }))
const editDistance = function (a, b, mem = [[0]]) {
mem[a.length] = mem[a.length] || [a.length]
if (mem[a.length][b.length] !== undefined) { return mem[a.length][b.length] }
const d = (a[a.length - 1] === b[b.length - 1]) ? 0 : 1
const distance = (a.length === 1 && b.length === 1)
? d
: Math.min(
((a.length > 0) ? editDistance(a.slice(0, -1), b, mem) + 1 : Infinity),
((b.length > 0) ? editDistance(a, b.slice(0, -1), mem) + 1 : Infinity),
((a.length > 0 && b.length > 0) ? editDistance(a.slice(0, -1), b.slice(0, -1), mem) + d : Infinity)
)
mem[a.length][b.length] = distance
return distance
}
describe('clear', () => {
it('empties the map', () => {
const map = SearchableMap.from(keyValues)
map.clear()
expect(Array.from(map.entries())).toEqual([])
})
})
describe('delete', () => {
it('deletes the entry at the given key', () => {
const map = SearchableMap.from(keyValues)
map.delete('border')
expect(map.has('border')).toBe(false)
expect(map.has('summer')).toBe(true)
expect(map.has('borderline')).toBe(true)
expect(map.has('bo')).toBe(true)
})
it('changes the size of the map', () => {
const map = SearchableMap.from(keyValues)
const sizeBefore = map.size
map.delete('summertime')
expect(map.size).toEqual(sizeBefore - 1)
})
it('does nothing if the entry did not exist', () => {
const map = new SearchableMap()
expect(() => map.delete('something')).not.toThrow()
})
it('leaves the radix tree in the same state as before the entry was added', () => {
const map = new SearchableMap()
map.set('hello', 1)
const before = new SearchableMap(new Map(map._tree))
map.set('help', 2)
map.delete('help')
expect(map).toEqual(before)
})
})
describe('entries', () => {
it('returns an iterator of entries', () => {
const map = SearchableMap.from(keyValues)
const entries = Array.from({ [Symbol.iterator]: () => map.entries() })
expect(entries.sort()).toEqual(keyValues.sort())
})
it('returns an iterable of entries', () => {
const map = SearchableMap.from(keyValues)
const entries = Array.from(map.entries())
expect(entries.sort()).toEqual(keyValues.sort())
})
it('returns empty iterator, if the map is empty', () => {
const map = new SearchableMap()
const entries = Array.from(map.entries())
expect(entries).toEqual([])
})
})
describe('forEach', () => {
it('iterates through each entry', () => {
const entries = []
const fn = (key, value) => entries.push([key, value])
const map = SearchableMap.from(keyValues)
map.forEach(fn)
expect(entries).toEqual(Array.from(map.entries()))
})
})
describe('get', () => {
it('gets the value at key', () => {
const key = 'foo'
const value = 42
const map = SearchableMap.fromObject({ [key]: value })
expect(map.get(key)).toBe(value)
})
it('returns undefined if the key is not present', () => {
const map = new SearchableMap()
expect(map.get('not-existent')).toBe(undefined)
})
})
describe('has', () => {
it('returns true if the given key exists in the map', () => {
const map = new SearchableMap()
map.set('something', 42)
expect(map.has('something')).toBe(true)
map.set('something else', null)
expect(map.has('something else')).toBe(true)
})
it('returns false if the given key does not exist in the map', () => {
const map = SearchableMap.fromObject({ something: 42 })
expect(map.has('not-existing')).toBe(false)
expect(map.has('some')).toBe(false)
})
})
describe('keys', () => {
it('returns an iterator of keys', () => {
const map = SearchableMap.from(keyValues)
const keys = Array.from({ [Symbol.iterator]: () => map.keys() })
expect(keys.sort()).toEqual(strings.sort())
})
it('returns an iterable of keys', () => {
const map = SearchableMap.from(keyValues)
const keys = Array.from(map.keys())
expect(keys.sort()).toEqual(strings.sort())
})
it('returns empty iterator, if the map is empty', () => {
const map = new SearchableMap()
const keys = Array.from(map.keys())
expect(keys).toEqual([])
})
})
describe('set', () => {
it('sets a value at key', () => {
const map = new SearchableMap()
const key = 'foo'
const value = 42
map.set(key, value)
expect(map.get(key)).toBe(value)
})
it('overrides a value at key if it already exists', () => {
const map = SearchableMap.fromObject({ foo: 123 })
const key = 'foo'
const value = 42
map.set(key, value)
expect(map.get(key)).toBe(value)
})
it('throws error if the given key is not a string', () => {
const map = new SearchableMap()
expect(() => map.set(123, 'foo')).toThrow('key must be a string')
})
})
describe('size', () => {
it('is a property containing the size of the map', () => {
const map = SearchableMap.from(keyValues)
expect(map.size).toEqual(keyValues.length)
map.set('foo', 42)
expect(map.size).toEqual(keyValues.length + 1)
map.delete('border')
expect(map.size).toEqual(keyValues.length)
map.clear()
expect(map.size).toEqual(0)
})
})
describe('update', () => {
it('sets a value at key applying a function to the previous value', () => {
const map = new SearchableMap()
const key = 'foo'
const fn = jest.fn(x => (x || 0) + 1)
map.update(key, fn)
expect(fn).toHaveBeenCalledWith(undefined)
expect(map.get(key)).toBe(1)
map.update(key, fn)
expect(fn).toHaveBeenCalledWith(1)
expect(map.get(key)).toBe(2)
})
it('throws error if the given key is not a string', () => {
const map = new SearchableMap()
expect(() => map.update(123, () => {})).toThrow('key must be a string')
})
})
describe('values', () => {
it('returns an iterator of values', () => {
const map = SearchableMap.fromObject(object)
const values = Array.from({ [Symbol.iterator]: () => map.values() })
expect(values.sort()).toEqual(Object.values(object).sort())
})
it('returns an iterable of values', () => {
const map = SearchableMap.fromObject(object)
const values = Array.from(map.values())
expect(values.sort()).toEqual(Object.values(object).sort())
})
it('returns empty iterator, if the map is empty', () => {
const map = new SearchableMap()
const values = Array.from(map.values())
expect(values).toEqual([])
})
})
describe('atPrefix', () => {
it('returns the submap at the given prefix', () => {
const map = SearchableMap.from(keyValues)
const sum = map.atPrefix('sum')
expect(Array.from(sum.keys()).sort()).toEqual(strings.filter(string => string.startsWith('sum')).sort())
const summer = sum.atPrefix('summer')
expect(Array.from(summer.keys()).sort()).toEqual(strings.filter(string => string.startsWith('summer')).sort())
const xyz = map.atPrefix('xyz')
expect(Array.from(xyz.keys())).toEqual([])
expect(() => sum.atPrefix('xyz')).toThrow()
})
it('correctly computes the size', () => {
const map = SearchableMap.from(keyValues)
const sum = map.atPrefix('sum')
expect(sum.size).toEqual(strings.filter(string => string.startsWith('sum')).length)
})
})
describe('fuzzyGet', () => {
const terms = ['summer', 'acqua', 'aqua', 'acquire', 'poisson', 'qua']
const keyValues = terms.map((key, i) => [key, i])
const map = SearchableMap.from(keyValues)
it('returns all entries having the given maximum edit distance from the given key', () => {
[0, 1, 2, 3].forEach(distance => {
const results = map.fuzzyGet('acqua', distance)
const entries = Array.from(results)
expect(entries.map(([key, [value, dist]]) => [key, dist]).sort())
.toEqual(terms.map(term => [term, editDistance('acqua', term)]).filter(([, d]) => d <= distance).sort())
expect(entries.every(([key, [value]]) => map.get(key) === value)).toBe(true)
})
})
it('returns an empty object if no matching entries are found', () => {
expect(map.fuzzyGet('winter', 1)).toEqual(new Map())
})
it('returns entries if edit distance is longer than key', () => {
const map = SearchableMap.from([['x', 1], [' x', 2]])
expect(Array.from(map.fuzzyGet('x', 2).values())).toEqual([[1, 0], [2, 1]])
})
})
describe('with generated test data', () => {
it('adds and removes entries', () => {
const arrayOfStrings = fc.array(fc.oneof(fc.unicodeString(), fc.string()), { maxLength: 70 })
const string = fc.oneof(fc.unicodeString({ minLength: 0, maxLength: 4 }), fc.string({ minLength: 0, maxLength: 4 }))
const int = fc.integer({ min: 1, max: 4 })
fc.assert(fc.property(arrayOfStrings, string, int, (terms, prefix, maxDist) => {
const map = new SearchableMap()
const standardMap = new Map()
const uniqueTerms = [...new Set(terms)]
terms.forEach((term, i) => {
map.set(term, i)
standardMap.set(term, i)
expect(map.has(term)).toBe(true)
expect(standardMap.get(term)).toEqual(i)
})
expect(map.size).toEqual(standardMap.size)
expect(Array.from(map.entries()).sort()).toEqual(Array.from(standardMap.entries()).sort())
expect(Array.from(map.atPrefix(prefix).keys()).sort())
.toEqual(Array.from(new Set(terms)).filter(t => t.startsWith(prefix)).sort())
const fuzzy = map.fuzzyGet(terms[0], maxDist)
expect(Array.from(fuzzy, ([key, [value, dist]]) => [key, dist]).sort())
.toEqual(uniqueTerms.map(term => [term, editDistance(terms[0], term)])
.filter(([, dist]) => dist <= maxDist).sort())
terms.forEach(term => {
map.delete(term)
expect(map.has(term)).toBe(false)
expect(map.get(term)).toEqual(undefined)
})
expect(map.size).toEqual(0)
}))
})
})
})

View file

@ -0,0 +1,422 @@
/* eslint-disable no-labels */
import { TreeIterator, ENTRIES, KEYS, VALUES, LEAF } from './TreeIterator'
import fuzzySearch, { FuzzyResults } from './fuzzySearch'
import { RadixTree, Entry, Path } from './types'
/**
* A class implementing the same interface as a standard JavaScript
* [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
* with string keys, but adding support for efficiently searching entries with
* prefix or fuzzy search. This class is used internally by [[MiniSearch]] as
* the inverted index data structure. The implementation is a radix tree
* (compressed prefix tree).
*
* Since this class can be of general utility beyond _MiniSearch_, it is
* exported by the `minisearch` package and can be imported (or required) as
* `minisearch/SearchableMap`.
*
* @typeParam T The type of the values stored in the map.
*/
export default class SearchableMap<T = any> {
/**
* @internal
*/
_tree: RadixTree<T>
/**
* @internal
*/
_prefix: string
private _size: number | undefined = undefined
/**
* The constructor is normally called without arguments, creating an empty
* map. In order to create a [[SearchableMap]] from an iterable or from an
* object, check [[SearchableMap.from]] and [[SearchableMap.fromObject]].
*
* The constructor arguments are for internal use, when creating derived
* mutable views of a map at a prefix.
*/
constructor (tree: RadixTree<T> = new Map(), prefix = '') {
this._tree = tree
this._prefix = prefix
}
/**
* Creates and returns a mutable view of this [[SearchableMap]], containing only
* entries that share the given prefix.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set("unicorn", 1)
* map.set("universe", 2)
* map.set("university", 3)
* map.set("unique", 4)
* map.set("hello", 5)
*
* let uni = map.atPrefix("uni")
* uni.get("unique") // => 4
* uni.get("unicorn") // => 1
* uni.get("hello") // => undefined
*
* let univer = map.atPrefix("univer")
* univer.get("unique") // => undefined
* univer.get("universe") // => 2
* univer.get("university") // => 3
* ```
*
* @param prefix The prefix
* @return A [[SearchableMap]] representing a mutable view of the original Map at the given prefix
*/
atPrefix (prefix: string): SearchableMap<T> {
if (!prefix.startsWith(this._prefix)) { throw new Error('Mismatched prefix') }
const [node, path] = trackDown(this._tree, prefix.slice(this._prefix.length))
if (node === undefined) {
const [parentNode, key] = last(path)
for (const k of parentNode!.keys()) {
if (k !== LEAF && k.startsWith(key)) {
const node = new Map()
node.set(k.slice(key.length), parentNode!.get(k)!)
return new SearchableMap(node, prefix)
}
}
}
return new SearchableMap<T>(node, prefix)
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear
*/
clear (): void {
this._size = undefined
this._tree.clear()
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete
* @param key Key to delete
*/
delete (key: string): void {
this._size = undefined
return remove(this._tree, key)
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries
* @return An iterator iterating through `[key, value]` entries.
*/
entries () {
return new TreeIterator(this, ENTRIES)
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/forEach
* @param fn Iteration function
*/
forEach (fn: (key: string, value: T, map: SearchableMap) => void): void {
for (const [key, value] of this) {
fn(key, value, this)
}
}
/**
* Returns a Map of all the entries that have a key within the given edit
* distance from the search key. The keys of the returned Map are the matching
* keys, while the values are two-element arrays where the first element is
* the value associated to the key, and the second is the edit distance of the
* key to the search key.
*
* ### Usage:
*
* ```javascript
* let map = new SearchableMap()
* map.set('hello', 'world')
* map.set('hell', 'yeah')
* map.set('ciao', 'mondo')
*
* // Get all entries that match the key 'hallo' with a maximum edit distance of 2
* map.fuzzyGet('hallo', 2)
* // => Map(2) { 'hello' => ['world', 1], 'hell' => ['yeah', 2] }
*
* // In the example, the "hello" key has value "world" and edit distance of 1
* // (change "e" to "a"), the key "hell" has value "yeah" and edit distance of 2
* // (change "e" to "a", delete "o")
* ```
*
* @param key The search key
* @param maxEditDistance The maximum edit distance (Levenshtein)
* @return A Map of the matching keys to their value and edit distance
*/
fuzzyGet (key: string, maxEditDistance: number): FuzzyResults<T> {
return fuzzySearch<T>(this._tree, key, maxEditDistance)
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
* @param key Key to get
* @return Value associated to the key, or `undefined` if the key is not
* found.
*/
get (key: string): T | undefined {
const node = lookup<T>(this._tree, key)
return node !== undefined ? node.get(LEAF) : undefined
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has
* @param key Key
* @return True if the key is in the map, false otherwise
*/
has (key: string): boolean {
const node = lookup(this._tree, key)
return node !== undefined && node.has(LEAF)
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys
* @return An `Iterable` iterating through keys
*/
keys () {
return new TreeIterator(this, KEYS)
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set
* @param key Key to set
* @param value Value to associate to the key
* @return The [[SearchableMap]] itself, to allow chaining
*/
set (key: string, value: T): SearchableMap<T> {
if (typeof key !== 'string') { throw new Error('key must be a string') }
this._size = undefined
const node = createPath(this._tree, key)
node.set(LEAF, value)
return this
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size
*/
get size (): number {
if (this._size) { return this._size }
/** @ignore */
this._size = 0
const iter = this.entries()
while (!iter.next().done) this._size! += 1
return this._size
}
/**
* Updates the value at the given key using the provided function. The function
* is called with the current value at the key, and its return value is used as
* the new value to be set.
*
* ### Example:
*
* ```javascript
* // Increment the current value by one
* searchableMap.update('somekey', (currentValue) => currentValue == null ? 0 : currentValue + 1)
* ```
*
* If the value at the given key is or will be an object, it might not require
* re-assignment. In that case it is better to use `fetch()`, because it is
* faster.
*
* @param key The key to update
* @param fn The function used to compute the new value from the current one
* @return The [[SearchableMap]] itself, to allow chaining
*/
update (key: string, fn: (value: T | undefined) => T): SearchableMap<T> {
if (typeof key !== 'string') { throw new Error('key must be a string') }
this._size = undefined
const node = createPath(this._tree, key)
node.set(LEAF, fn(node.get(LEAF)))
return this
}
/**
* Fetches the value of the given key. If the value does not exist, calls the
* given function to create a new value, which is inserted at the given key
* and subsequently returned.
*
* ### Example:
*
* ```javascript
* const map = searchableMap.fetch('somekey', () => new Map())
* map.set('foo', 'bar')
* ```
*
* @param key The key to update
* @param defaultValue A function that creates a new value if the key does not exist
* @return The existing or new value at the given key
*/
fetch (key: string, initial: () => T): T {
if (typeof key !== 'string') { throw new Error('key must be a string') }
this._size = undefined
const node = createPath(this._tree, key)
let value = node.get(LEAF)
if (value === undefined) {
node.set(LEAF, value = initial())
}
return value
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values
* @return An `Iterable` iterating through values.
*/
values () {
return new TreeIterator(this, VALUES)
}
/**
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@iterator
*/
[Symbol.iterator] () {
return this.entries()
}
/**
* Creates a [[SearchableMap]] from an `Iterable` of entries
*
* @param entries Entries to be inserted in the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
static from<T = any> (entries: Iterable<Entry<T>> | Entry<T>[]) {
const tree = new SearchableMap()
for (const [key, value] of entries) {
tree.set(key, value)
}
return tree
}
/**
* Creates a [[SearchableMap]] from the iterable properties of a JavaScript object
*
* @param object Object of entries for the [[SearchableMap]]
* @return A new [[SearchableMap]] with the given entries
*/
static fromObject<T = any> (object: { [key: string]: T }) {
return SearchableMap.from<T>(Object.entries(object))
}
}
const trackDown = <T = any>(tree: RadixTree<T> | undefined, key: string, path: Path<T> = []): [RadixTree<T> | undefined, Path<T>] => {
if (key.length === 0 || tree == null) { return [tree, path] }
for (const k of tree.keys()) {
if (k !== LEAF && key.startsWith(k)) {
path.push([tree, k]) // performance: update in place
return trackDown(tree.get(k)!, key.slice(k.length), path)
}
}
path.push([tree, key]) // performance: update in place
return trackDown(undefined, '', path)
}
const lookup = <T = any>(tree: RadixTree<T>, key: string): RadixTree<T> | undefined => {
if (key.length === 0 || tree == null) { return tree }
for (const k of tree.keys()) {
if (k !== LEAF && key.startsWith(k)) {
return lookup(tree.get(k)!, key.slice(k.length))
}
}
}
// Create a path in the radix tree for the given key, and returns the deepest
// node. This function is in the hot path for indexing. It avoids unnecessary
// string operations and recursion for performance.
const createPath = <T = any>(node: RadixTree<T>, key: string): RadixTree<T> => {
const keyLength = key.length
outer: for (let pos = 0; node && pos < keyLength;) {
for (const k of node.keys()) {
// Check whether this key is a candidate: the first characters must match.
if (k !== LEAF && key[pos] === k[0]) {
const len = Math.min(keyLength - pos, k.length)
// Advance offset to the point where key and k no longer match.
let offset = 1
while (offset < len && key[pos + offset] === k[offset]) ++offset
const child = node.get(k)!
if (offset === k.length) {
// The existing key is shorter than the key we need to create.
node = child
} else {
// Partial match: we need to insert an intermediate node to contain
// both the existing subtree and the new node.
const intermediate = new Map()
intermediate.set(k.slice(offset), child)
node.set(key.slice(pos, pos + offset), intermediate)
node.delete(k)
node = intermediate
}
pos += offset
continue outer
}
}
// Create a final child node to contain the final suffix of the key.
const child = new Map()
node.set(key.slice(pos), child)
return child
}
return node
}
const remove = <T = any>(tree: RadixTree<T>, key: string): void => {
const [node, path] = trackDown(tree, key)
if (node === undefined) { return }
node.delete(LEAF)
if (node.size === 0) {
cleanup(path)
} else if (node.size === 1) {
const [key, value] = node.entries().next().value
merge(path, key, value)
}
}
const cleanup = <T = any>(path: Path<T>): void => {
if (path.length === 0) { return }
const [node, key] = last(path)
node!.delete(key)
if (node!.size === 0) {
cleanup(path.slice(0, -1))
} else if (node!.size === 1) {
const [key, value] = node!.entries().next().value
if (key !== LEAF) {
merge(path.slice(0, -1), key, value)
}
}
}
const merge = <T = any>(path: Path<T>, key: string, value: RadixTree<T>): void => {
if (path.length === 0) { return }
const [node, nodeKey] = last(path)
node!.set(nodeKey + key, value)
node!.delete(nodeKey)
}
const last = <T = any>(array: T[]): T => {
return array[array.length - 1]
}

View file

@ -0,0 +1,103 @@
import { RadixTree, Entry, LeafType } from './types'
/** @ignore */
const ENTRIES = 'ENTRIES'
/** @ignore */
const KEYS = 'KEYS'
/** @ignore */
const VALUES = 'VALUES'
/** @ignore */
const LEAF = '' as LeafType
interface Iterators<T> {
ENTRIES: Entry<T>
KEYS: string
VALUES: T
}
type Kind<T> = keyof Iterators<T>
type Result<T, K extends keyof Iterators<T>> = Iterators<T>[K]
type IteratorPath<T> = {
node: RadixTree<T>,
keys: string[]
}[]
export type IterableSet<T> = {
_tree: RadixTree<T>,
_prefix: string
}
/**
* @private
*/
class TreeIterator<T, K extends Kind<T>> implements Iterator<Result<T, K>> {
set: IterableSet<T>
_type: K
_path: IteratorPath<T>
constructor (set: IterableSet<T>, type: K) {
const node = set._tree
const keys = Array.from(node.keys())
this.set = set
this._type = type
this._path = keys.length > 0 ? [{ node, keys }] : []
}
next (): IteratorResult<Result<T, K>> {
const value = this.dive()
this.backtrack()
return value
}
dive (): IteratorResult<Result<T, K>> {
if (this._path.length === 0) { return { done: true, value: undefined } }
const { node, keys } = last(this._path)!
if (last(keys) === LEAF) { return { done: false, value: this.result() } }
const child = node.get(last(keys)!)!
this._path.push({ node: child, keys: Array.from(child.keys()) })
return this.dive()
}
backtrack (): void {
if (this._path.length === 0) { return }
const keys = last(this._path)!.keys
keys.pop()
if (keys.length > 0) { return }
this._path.pop()
this.backtrack()
}
key (): string {
return this.set._prefix + this._path
.map(({ keys }) => last(keys))
.filter(key => key !== LEAF)
.join('')
}
value (): T {
return last(this._path)!.node.get(LEAF)!
}
result (): Result<T, K> {
switch (this._type) {
case VALUES: return this.value() as Result<T, K>
case KEYS: return this.key() as Result<T, K>
default: return [this.key(), this.value()] as Result<T, K>
}
}
[Symbol.iterator] () {
return this
}
}
const last = <T>(array: T[]): T | undefined => {
return array[array.length - 1]
}
export { TreeIterator, ENTRIES, KEYS, VALUES, LEAF }

View file

@ -0,0 +1,130 @@
/* eslint-disable no-labels */
import { LEAF } from './TreeIterator'
import { RadixTree } from './types'
export type FuzzyResult<T> = [T, number]
export type FuzzyResults<T> = Map<string, FuzzyResult<T>>
/**
* @ignore
*/
export const fuzzySearch = <T = any>(node: RadixTree<T>, query: string, maxDistance: number): FuzzyResults<T> => {
const results: FuzzyResults<T> = new Map()
if (query === undefined) return results
// Number of columns in the Levenshtein matrix.
const n = query.length + 1
// Matching terms can never be longer than N + maxDistance.
const m = n + maxDistance
// Fill first matrix row and column with numbers: 0 1 2 3 ...
const matrix = new Uint8Array(m * n).fill(maxDistance + 1)
for (let j = 0; j < n; ++j) matrix[j] = j
for (let i = 1; i < m; ++i) matrix[i * n] = i
recurse(
node,
query,
maxDistance,
results,
matrix,
1,
n,
''
)
return results
}
// Modified version of http://stevehanov.ca/blog/?id=114
// This builds a Levenshtein matrix for a given query and continuously updates
// it for nodes in the radix tree that fall within the given maximum edit
// distance. Keeping the same matrix around is beneficial especially for larger
// edit distances.
//
// k a t e <-- query
// 0 1 2 3 4
// c 1 1 2 3 4
// a 2 2 1 2 3
// t 3 3 2 1 [2] <-- edit distance
// ^
// ^ term in radix tree, rows are added and removed as needed
const recurse = <T = any>(
node: RadixTree<T>,
query: string,
maxDistance: number,
results: FuzzyResults<T>,
matrix: Uint8Array,
m: number,
n: number,
prefix: string
): void => {
const offset = m * n
key: for (const key of node.keys()) {
if (key === LEAF) {
// We've reached a leaf node. Check if the edit distance acceptable and
// store the result if it is.
const distance = matrix[offset - 1]
if (distance <= maxDistance) {
results.set(prefix, [node.get(key)!, distance])
}
} else {
// Iterate over all characters in the key. Update the Levenshtein matrix
// and check if the minimum distance in the last row is still within the
// maximum edit distance. If it is, we can recurse over all child nodes.
let i = m
for (let pos = 0; pos < key.length; ++pos, ++i) {
const char = key[pos]
const thisRowOffset = n * i
const prevRowOffset = thisRowOffset - n
// Set the first column based on the previous row, and initialize the
// minimum distance in the current row.
let minDistance = matrix[thisRowOffset]
const jmin = Math.max(0, i - maxDistance - 1)
const jmax = Math.min(n - 1, i + maxDistance)
// Iterate over remaining columns (characters in the query).
for (let j = jmin; j < jmax; ++j) {
const different = char !== query[j]
// It might make sense to only read the matrix positions used for
// deletion/insertion if the characters are different. But we want to
// avoid conditional reads for performance reasons.
const rpl = matrix[prevRowOffset + j] + +different
const del = matrix[prevRowOffset + j + 1] + 1
const ins = matrix[thisRowOffset + j] + 1
const dist = matrix[thisRowOffset + j + 1] = Math.min(rpl, del, ins)
if (dist < minDistance) minDistance = dist
}
// Because distance will never decrease, we can stop. There will be no
// matching child nodes.
if (minDistance > maxDistance) {
continue key
}
}
recurse(
node.get(key)!,
query,
maxDistance,
results,
matrix,
i,
n,
prefix + key
)
}
}
}
export default fuzzySearch

18
node_modules/minisearch/src/SearchableMap/types.ts generated vendored Normal file
View file

@ -0,0 +1,18 @@
export type LeafType = '' & { readonly __tag: unique symbol }
export interface RadixTree<T> extends Map<string, T | RadixTree<T>> {
// Distinguish between an empty string indicating a leaf node and a non-empty
// string indicating a subtree. Overriding these types avoids a lot of type
// assertions elsewhere in the code. It is not 100% foolproof because you can
// still pass in a blank string '' disguised as `string` and potentially get a
// leaf value.
get(key: LeafType): T | undefined
get(key: string): RadixTree<T> | undefined
set(key: LeafType, value: T): this
set(key: string, value: RadixTree<T>): this
}
export type Entry<T> = [string, T]
export type Path<T> = [RadixTree<T> | undefined, string][]

4
node_modules/minisearch/src/index.ts generated vendored Normal file
View file

@ -0,0 +1,4 @@
import MiniSearch from './MiniSearch'
export * from './MiniSearch'
export default MiniSearch

1
node_modules/minisearch/src/testSetup/jest.js generated vendored Normal file
View file

@ -0,0 +1 @@
/* eslint-env jest */