mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-26 10:33:44 +03:00
fix: reduce search index size
This commit is contained in:
parent
8afae474c7
commit
a1fa4b47a8
|
@ -5,7 +5,7 @@ import { SearchStore } from '../../services/SearchStore';
|
|||
import { MenuItem } from '../SideMenu/MenuItem';
|
||||
|
||||
import { MarkerService } from '../../services/MarkerService';
|
||||
import { SearchDocument } from '../../services/SearchWorker.worker';
|
||||
import { SearchResult } from '../../services/SearchWorker.worker';
|
||||
|
||||
import {
|
||||
ClearIcon,
|
||||
|
@ -16,7 +16,7 @@ import {
|
|||
} from './styled.elements';
|
||||
|
||||
export interface SearchBoxProps {
|
||||
search: SearchStore;
|
||||
search: SearchStore<string>;
|
||||
marker: MarkerService;
|
||||
getItemById: (id: string) => IMenuItem | undefined;
|
||||
onActivate: (item: IMenuItem) => void;
|
||||
|
@ -25,16 +25,11 @@ export interface SearchBoxProps {
|
|||
}
|
||||
|
||||
export interface SearchBoxState {
|
||||
results: any;
|
||||
results: SearchResult[];
|
||||
term: string;
|
||||
activeItemIdx: number;
|
||||
}
|
||||
|
||||
interface SearchResult {
|
||||
item: IMenuItem;
|
||||
score: number;
|
||||
}
|
||||
|
||||
export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxState> {
|
||||
activeItemRef: MenuItem | null = null;
|
||||
|
||||
|
@ -87,7 +82,7 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat
|
|||
// enter
|
||||
const activeResult = this.state.results[this.state.activeItemIdx];
|
||||
if (activeResult) {
|
||||
const item = this.props.getItemById(activeResult.id);
|
||||
const item = this.props.getItemById(activeResult.meta);
|
||||
if (item) {
|
||||
this.props.onActivate(item);
|
||||
}
|
||||
|
@ -95,7 +90,7 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat
|
|||
}
|
||||
};
|
||||
|
||||
setResults(results: SearchDocument[], term: string) {
|
||||
setResults(results: SearchResult[], term: string) {
|
||||
this.setState({
|
||||
results,
|
||||
term,
|
||||
|
@ -121,8 +116,8 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat
|
|||
|
||||
render() {
|
||||
const { activeItemIdx } = this.state;
|
||||
const results: SearchResult[] = this.state.results.map(res => ({
|
||||
item: this.props.getItemById(res.id),
|
||||
const results = this.state.results.map(res => ({
|
||||
item: this.props.getItemById(res.meta)!,
|
||||
score: res.score,
|
||||
}));
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ export class AppStore {
|
|||
spec: SpecStore;
|
||||
rawOptions: RedocRawOptions;
|
||||
options: RedocNormalizedOptions;
|
||||
search: SearchStore;
|
||||
search: SearchStore<string>;
|
||||
marker = new MarkerService();
|
||||
|
||||
private scroll: ScrollService;
|
||||
|
|
|
@ -17,7 +17,7 @@ if (IS_BROWSER) {
|
|||
worker = require('./SearchWorker.worker').default;
|
||||
}
|
||||
|
||||
export class SearchStore {
|
||||
export class SearchStore<T> {
|
||||
searchWorker = new worker();
|
||||
|
||||
indexItems(groups: Array<IMenuItem | OperationModel>) {
|
||||
|
@ -34,12 +34,12 @@ export class SearchStore {
|
|||
this.searchWorker.done();
|
||||
}
|
||||
|
||||
add(title: string, body: string, ref: string) {
|
||||
this.searchWorker.add(title, body, ref);
|
||||
add(title: string, body: string, meta?: T) {
|
||||
this.searchWorker.add(title, body, meta);
|
||||
}
|
||||
|
||||
search(q: string) {
|
||||
return this.searchWorker.search(q);
|
||||
return this.searchWorker.search<T>(q);
|
||||
}
|
||||
|
||||
async toJS() {
|
||||
|
|
|
@ -2,9 +2,9 @@ import * as lunr from 'lunr';
|
|||
|
||||
/* just for better typings */
|
||||
export default class Worker {
|
||||
add = add;
|
||||
add: typeof add = add;
|
||||
done = done;
|
||||
search = search;
|
||||
search: typeof search = search;
|
||||
toJS = toJS;
|
||||
load = load;
|
||||
}
|
||||
|
@ -15,11 +15,12 @@ export interface SearchDocument {
|
|||
id: string;
|
||||
}
|
||||
|
||||
export interface SearchResult extends SearchDocument {
|
||||
export interface SearchResult<T = string> {
|
||||
meta: T;
|
||||
score: number;
|
||||
}
|
||||
|
||||
let store: { [id: string]: SearchDocument } = {};
|
||||
let store: any[] = [];
|
||||
|
||||
let resolveIndex: (v: lunr.Index) => void = () => {
|
||||
throw new Error('Should not be called');
|
||||
|
@ -29,19 +30,21 @@ const index: Promise<lunr.Index> = new Promise(resolve => {
|
|||
resolveIndex = resolve;
|
||||
});
|
||||
|
||||
lunr.tokenizer.separator = /\s+/;
|
||||
|
||||
const builder = new lunr.Builder();
|
||||
builder.field('title');
|
||||
builder.field('description');
|
||||
builder.ref('id');
|
||||
builder.ref('ref');
|
||||
|
||||
builder.pipeline.add(lunr.trimmer, lunr.stopWordFilter, lunr.stemmer);
|
||||
|
||||
const expandTerm = term => '*' + lunr.stemmer(new lunr.Token(term, {})) + '*';
|
||||
|
||||
export function add(title: string, description: string, id: string) {
|
||||
const item = { title, description, id };
|
||||
export function add<T>(title: string, description: string, meta?: T) {
|
||||
const ref = store.push(meta) - 1;
|
||||
const item = { title: title.toLowerCase(), description: description.toLowerCase(), ref };
|
||||
builder.add(item);
|
||||
store[id] = item;
|
||||
}
|
||||
|
||||
export async function done() {
|
||||
|
@ -60,20 +63,28 @@ export async function load(state: any) {
|
|||
resolveIndex(lunr.Index.load(state.index));
|
||||
}
|
||||
|
||||
export async function search(q: string): Promise<Array<SearchDocument & SearchResult>> {
|
||||
export async function search<Meta = string>(
|
||||
q: string,
|
||||
limit = 0,
|
||||
): Promise<Array<SearchResult<Meta>>> {
|
||||
if (q.trim().length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return (await index)
|
||||
.query(t => {
|
||||
let searchResults = (await index).query(t => {
|
||||
q
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.split(/\s+/)
|
||||
.forEach(term => {
|
||||
const exp = expandTerm(term);
|
||||
t.term(exp, {});
|
||||
});
|
||||
})
|
||||
.map(res => ({ ...store[res.ref], score: res.score }));
|
||||
});
|
||||
|
||||
if (limit > 0) {
|
||||
searchResults = searchResults.slice(0, limit);
|
||||
}
|
||||
|
||||
return searchResults.map(res => ({ meta: store[res.ref], score: res.score }));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user