feat: serialize search-index

This commit is contained in:
Roman Hotsiy 2018-03-06 13:10:08 +02:00
parent 8e4184b407
commit e94f84283d
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
5 changed files with 51 additions and 19 deletions

View File

@ -35,12 +35,12 @@ async function init() {
init();
if (module.hot) {
const reload = (reloadStore = false) => () => {
const reload = (reloadStore = false) => async () => {
if (reloadStore) {
// create a new Store
store.dispose();
const state = store.toJS();
const state = await store.toJS();
store = AppStore.fromJS(state);
}

View File

@ -72,7 +72,7 @@
"webpack": "^3.10.0",
"webpack-dev-server": "^2.9.5",
"webpack-node-externals": "^1.6.0",
"workerize-loader": "^1.0.1",
"workerize-loader": "^1.0.2",
"yaml-js": "^0.2.3"
},
"peerDependencies": {

View File

@ -17,6 +17,7 @@ interface StoreData {
url: string;
data: any;
};
searchIndex: any;
options: RedocRawOptions;
}
@ -36,9 +37,10 @@ export class AppStore {
*/
// TODO:
static fromJS(state: StoreData): AppStore {
const inst = new AppStore(state.spec.data, state.spec.url, state.options);
const inst = new AppStore(state.spec.data, state.spec.url, state.options, false);
inst.menu.activeItemIdx = state.menu.activeItemIdx || 0;
inst.menu.activate(inst.menu.flatItems[inst.menu.activeItemIdx]);
inst.search.load(state.searchIndex);
return inst;
}
@ -52,7 +54,12 @@ export class AppStore {
private scroll: ScrollService;
private disposer;
constructor(spec: OpenAPISpec, specUrl?: string, options: RedocRawOptions = {}) {
constructor(
spec: OpenAPISpec,
specUrl?: string,
options: RedocRawOptions = {},
createSearchIndex: boolean = true,
) {
this.rawOptions = options;
this.options = new RedocNormalizedOptions(options);
this.scroll = new ScrollService(this.options);
@ -60,8 +67,9 @@ export class AppStore {
this.menu = new MenuStore(this.spec, this.scroll);
this.search = new SearchStore();
this.search.indexItems(this.menu.items);
this.search.done();
if (createSearchIndex) {
this.search.indexItems(this.menu.items);
}
this.disposer = observe(this.menu, 'activeItemIdx', change => {
this.updateMarkOnMenu(change.newValue as number);
@ -106,7 +114,7 @@ export class AppStore {
* **SUPER HACKY AND NOT OPTIMAL IMPLEMENTATION**
*/
// TODO:
toJS(): StoreData {
async toJS(): Promise<StoreData> {
return {
menu: {
activeItemIdx: this.menu.activeItemIdx,
@ -115,6 +123,7 @@ export class AppStore {
url: this.spec.parser.specUrl,
data: this.spec.parser.spec,
},
searchIndex: await this.search.toJS(),
options: this.rawOptions,
};
}

View File

@ -6,23 +6,32 @@ export class SearchStore {
searchWorker = new worker();
indexItems(groups: Array<IMenuItem | OperationModel>) {
groups.forEach(group => {
if (group.type !== 'group') {
this.add(group.name, group.description || '', group.id);
}
this.indexItems(group.items);
});
const recurse = groups => {
groups.forEach(group => {
if (group.type !== 'group') {
this.add(group.name, group.description || '', group.id);
}
recurse(group.items);
});
};
recurse(groups);
this.searchWorker.done();
}
add(title: string, body: string, ref: string) {
this.searchWorker.add(title, body, ref);
}
done() {
this.searchWorker.done();
}
search(q: string) {
return this.searchWorker.search(q);
}
async toJS() {
return this.searchWorker.toJS();
}
load(state: any) {
this.searchWorker.load(state);
}
}

View File

@ -5,6 +5,8 @@ export default class Worker {
add = add;
done = done;
search = search;
toJS = toJS;
load = load;
}
export interface SearchDocument {
@ -17,7 +19,7 @@ export interface SearchResult extends SearchDocument {
score: number;
}
const store: { [id: string]: SearchDocument } = {};
let store: { [id: string]: SearchDocument } = {};
let resolveIndex: (v: lunr.Index) => void;
const index: Promise<lunr.Index> = new Promise(resolve => {
@ -43,6 +45,18 @@ export async function done() {
resolveIndex(builder.build());
}
export async function toJS() {
return {
store: store,
index: (await index).toJSON(),
};
}
export async function load(state: any) {
store = state.store;
resolveIndex(lunr.Index.load(state.index));
}
export async function search(q: string): Promise<SearchResult[]> {
if (q.trim().length === 0) {
return [];