discourse/app/assets/javascripts/admin/addon/lib/site-setting-matcher.js
Ted Johansson b056f9538b
DEV: Improve site setting search ranking (#32461)
This change does a couple of things.

Change in behaviour:

- Matches on the site setting name and keywords now get a higher ranking in search results.
- When counting gaps for ranking fuzzy matches, we no consider the smallest number of gaps.

Code organization:

- Extract a separate SiteSettingMatcher object for the matching logic.
- Flatten some conditionals to make control flow clearer.
- Higher weight now means higher in search results.
2025-04-28 16:58:27 +08:00

75 lines
1.8 KiB
JavaScript
Vendored

export default class SiteSettingMatcher {
constructor(filter, siteSetting) {
this.filter = filter;
this.siteSetting = siteSetting;
this.strippedQuery = filter.replace(/[^a-z0-9]/gi, "");
this.fuzzyRegex = new RegExp(this.strippedQuery.split("").join(".*"), "i");
this.fuzzyRegexGaps = new RegExp(
".*" + this.strippedQuery.split("").join("(.*)"),
"i"
);
this.matchStrength = 0;
}
get isNameMatch() {
const name = this.siteSetting.setting.toLowerCase();
return (
name.includes(this.filter) ||
name.replace(/_/g, " ").includes(this.filter)
);
}
get isKeywordMatch() {
return (this.siteSetting.keywords || []).any((keyword) =>
keyword
.replace(/_/g, " ")
.toLowerCase()
.includes(this.filter.replace(/_/g, " "))
);
}
get isDescriptionMatch() {
return this.siteSetting.description.toLowerCase().includes(this.filter);
}
get isValueMatch() {
return (this.siteSetting.value || "")
.toString()
.toLowerCase()
.includes(this.filter);
}
get isFuzzyNameMatch() {
const name = this.siteSetting.setting.toLowerCase();
if (this.strippedQuery.length < 3) {
return false;
}
if (!this.fuzzyRegex.test(name)) {
return false;
}
const fuzzySearchLimiter = 25;
const strippedSetting = name.replace(/[^a-z0-9]/gi, "");
if (
strippedSetting.length >
this.strippedQuery.length + fuzzySearchLimiter
) {
return false;
}
const gapResult = strippedSetting.match(this.fuzzyRegexGaps);
if (gapResult) {
// Discard empty gaps and disregard the full string match.
const numberOfGaps = gapResult.filter((gap) => gap !== "").length - 1;
this.matchStrength -= numberOfGaps;
}
return true;
}
}