mirror of
https://github.com/Redocly/redoc.git
synced 2025-07-11 00:32:36 +03:00
feat: serialize search-index
This commit is contained in:
parent
8e4184b407
commit
e94f84283d
|
@ -35,12 +35,12 @@ async function init() {
|
||||||
init();
|
init();
|
||||||
|
|
||||||
if (module.hot) {
|
if (module.hot) {
|
||||||
const reload = (reloadStore = false) => () => {
|
const reload = (reloadStore = false) => async () => {
|
||||||
if (reloadStore) {
|
if (reloadStore) {
|
||||||
// create a new Store
|
// create a new Store
|
||||||
store.dispose();
|
store.dispose();
|
||||||
|
|
||||||
const state = store.toJS();
|
const state = await store.toJS();
|
||||||
store = AppStore.fromJS(state);
|
store = AppStore.fromJS(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
"webpack": "^3.10.0",
|
"webpack": "^3.10.0",
|
||||||
"webpack-dev-server": "^2.9.5",
|
"webpack-dev-server": "^2.9.5",
|
||||||
"webpack-node-externals": "^1.6.0",
|
"webpack-node-externals": "^1.6.0",
|
||||||
"workerize-loader": "^1.0.1",
|
"workerize-loader": "^1.0.2",
|
||||||
"yaml-js": "^0.2.3"
|
"yaml-js": "^0.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
@ -17,6 +17,7 @@ interface StoreData {
|
||||||
url: string;
|
url: string;
|
||||||
data: any;
|
data: any;
|
||||||
};
|
};
|
||||||
|
searchIndex: any;
|
||||||
options: RedocRawOptions;
|
options: RedocRawOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,9 +37,10 @@ export class AppStore {
|
||||||
*/
|
*/
|
||||||
// TODO:
|
// TODO:
|
||||||
static fromJS(state: StoreData): AppStore {
|
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.activeItemIdx = state.menu.activeItemIdx || 0;
|
||||||
inst.menu.activate(inst.menu.flatItems[inst.menu.activeItemIdx]);
|
inst.menu.activate(inst.menu.flatItems[inst.menu.activeItemIdx]);
|
||||||
|
inst.search.load(state.searchIndex);
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +54,12 @@ export class AppStore {
|
||||||
private scroll: ScrollService;
|
private scroll: ScrollService;
|
||||||
private disposer;
|
private disposer;
|
||||||
|
|
||||||
constructor(spec: OpenAPISpec, specUrl?: string, options: RedocRawOptions = {}) {
|
constructor(
|
||||||
|
spec: OpenAPISpec,
|
||||||
|
specUrl?: string,
|
||||||
|
options: RedocRawOptions = {},
|
||||||
|
createSearchIndex: boolean = true,
|
||||||
|
) {
|
||||||
this.rawOptions = options;
|
this.rawOptions = options;
|
||||||
this.options = new RedocNormalizedOptions(options);
|
this.options = new RedocNormalizedOptions(options);
|
||||||
this.scroll = new ScrollService(this.options);
|
this.scroll = new ScrollService(this.options);
|
||||||
|
@ -60,8 +67,9 @@ export class AppStore {
|
||||||
this.menu = new MenuStore(this.spec, this.scroll);
|
this.menu = new MenuStore(this.spec, this.scroll);
|
||||||
|
|
||||||
this.search = new SearchStore();
|
this.search = new SearchStore();
|
||||||
|
if (createSearchIndex) {
|
||||||
this.search.indexItems(this.menu.items);
|
this.search.indexItems(this.menu.items);
|
||||||
this.search.done();
|
}
|
||||||
|
|
||||||
this.disposer = observe(this.menu, 'activeItemIdx', change => {
|
this.disposer = observe(this.menu, 'activeItemIdx', change => {
|
||||||
this.updateMarkOnMenu(change.newValue as number);
|
this.updateMarkOnMenu(change.newValue as number);
|
||||||
|
@ -106,7 +114,7 @@ export class AppStore {
|
||||||
* **SUPER HACKY AND NOT OPTIMAL IMPLEMENTATION**
|
* **SUPER HACKY AND NOT OPTIMAL IMPLEMENTATION**
|
||||||
*/
|
*/
|
||||||
// TODO:
|
// TODO:
|
||||||
toJS(): StoreData {
|
async toJS(): Promise<StoreData> {
|
||||||
return {
|
return {
|
||||||
menu: {
|
menu: {
|
||||||
activeItemIdx: this.menu.activeItemIdx,
|
activeItemIdx: this.menu.activeItemIdx,
|
||||||
|
@ -115,6 +123,7 @@ export class AppStore {
|
||||||
url: this.spec.parser.specUrl,
|
url: this.spec.parser.specUrl,
|
||||||
data: this.spec.parser.spec,
|
data: this.spec.parser.spec,
|
||||||
},
|
},
|
||||||
|
searchIndex: await this.search.toJS(),
|
||||||
options: this.rawOptions,
|
options: this.rawOptions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,23 +6,32 @@ export class SearchStore {
|
||||||
searchWorker = new worker();
|
searchWorker = new worker();
|
||||||
|
|
||||||
indexItems(groups: Array<IMenuItem | OperationModel>) {
|
indexItems(groups: Array<IMenuItem | OperationModel>) {
|
||||||
|
const recurse = groups => {
|
||||||
groups.forEach(group => {
|
groups.forEach(group => {
|
||||||
if (group.type !== 'group') {
|
if (group.type !== 'group') {
|
||||||
this.add(group.name, group.description || '', group.id);
|
this.add(group.name, group.description || '', group.id);
|
||||||
}
|
}
|
||||||
this.indexItems(group.items);
|
recurse(group.items);
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
recurse(groups);
|
||||||
|
this.searchWorker.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
add(title: string, body: string, ref: string) {
|
add(title: string, body: string, ref: string) {
|
||||||
this.searchWorker.add(title, body, ref);
|
this.searchWorker.add(title, body, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
done() {
|
|
||||||
this.searchWorker.done();
|
|
||||||
}
|
|
||||||
|
|
||||||
search(q: string) {
|
search(q: string) {
|
||||||
return this.searchWorker.search(q);
|
return this.searchWorker.search(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async toJS() {
|
||||||
|
return this.searchWorker.toJS();
|
||||||
|
}
|
||||||
|
|
||||||
|
load(state: any) {
|
||||||
|
this.searchWorker.load(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ export default class Worker {
|
||||||
add = add;
|
add = add;
|
||||||
done = done;
|
done = done;
|
||||||
search = search;
|
search = search;
|
||||||
|
toJS = toJS;
|
||||||
|
load = load;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchDocument {
|
export interface SearchDocument {
|
||||||
|
@ -17,7 +19,7 @@ export interface SearchResult extends SearchDocument {
|
||||||
score: number;
|
score: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const store: { [id: string]: SearchDocument } = {};
|
let store: { [id: string]: SearchDocument } = {};
|
||||||
|
|
||||||
let resolveIndex: (v: lunr.Index) => void;
|
let resolveIndex: (v: lunr.Index) => void;
|
||||||
const index: Promise<lunr.Index> = new Promise(resolve => {
|
const index: Promise<lunr.Index> = new Promise(resolve => {
|
||||||
|
@ -43,6 +45,18 @@ export async function done() {
|
||||||
resolveIndex(builder.build());
|
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[]> {
|
export async function search(q: string): Promise<SearchResult[]> {
|
||||||
if (q.trim().length === 0) {
|
if (q.trim().length === 0) {
|
||||||
return [];
|
return [];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user