import SearchUtils from "./SearchUtils" import ThemeSearch from "./ThemeSearch" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" import { Strings } from "../../Utils/Strings" export default class LayerSearch { private readonly _theme: ThemeConfig private readonly _layerWhitelist: Set constructor(theme: ThemeConfig) { this._theme = theme this._layerWhitelist = new Set(theme.layers.filter((l) => l.isNormal()).map((l) => l.id)) } static scoreLayers( query: string, options: { whitelist?: Set blacklist?: Set } ): Record { const result: Record = {} const queryParts = query .trim() .split(" ") .map((q) => Strings.simplifyStringForSearch(q)) for (const id in ThemeSearch.officialThemes.layers) { if (options?.whitelist && !options?.whitelist.has(id)) { continue } if (options?.blacklist?.has(id)) { continue } const keywords = ThemeSearch.officialThemes.layers[id] result[id] = Math.min(...queryParts.map((q) => SearchUtils.scoreKeywords(q, keywords))) } return result } public search(query: string, limit: number, scoreThreshold: number = 2): LayerConfig[] { if (query.length < 1) { return [] } const scores = LayerSearch.scoreLayers(query, { whitelist: this._layerWhitelist }) const asList: { layer: LayerConfig; score: number }[] = [] for (const layer in scores) { asList.push({ layer: this._theme.getLayer(layer), score: scores[layer], }) } asList.sort((a, b) => a.score - b.score) return asList .filter((sorted) => sorted.score < scoreThreshold) .slice(0, limit) .map((l) => l.layer) } }