mirror of
https://github.com/freeCodeCamp/devdocs
synced 2024-11-16 19:48:10 +01:00
Sanity-check decaffeinate app.Searcher
This commit is contained in:
parent
978d4a9f64
commit
efb3697622
1 changed files with 190 additions and 226 deletions
|
@ -1,16 +1,3 @@
|
|||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Sanity-check the conversion and remove this comment.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS104: Avoid inline assignments
|
||||
* DS202: Simplify dynamic range loops
|
||||
* DS206: Consider reworking classes to avoid initClass
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* DS209: Avoid top-level return
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
|
||||
*/
|
||||
//
|
||||
// Match functions
|
||||
//
|
||||
|
@ -158,249 +145,226 @@ function scoreFuzzyMatch() {
|
|||
// Searchers
|
||||
//
|
||||
|
||||
(function () {
|
||||
let CHUNK_SIZE = undefined;
|
||||
let DEFAULTS = undefined;
|
||||
let SEPARATORS_REGEXP = undefined;
|
||||
let EOS_SEPARATORS_REGEXP = undefined;
|
||||
let INFO_PARANTHESES_REGEXP = undefined;
|
||||
let EMPTY_PARANTHESES_REGEXP = undefined;
|
||||
let EVENT_REGEXP = undefined;
|
||||
let DOT_REGEXP = undefined;
|
||||
let WHITESPACE_REGEXP = undefined;
|
||||
let EMPTY_STRING = undefined;
|
||||
let ELLIPSIS = undefined;
|
||||
let STRING = undefined;
|
||||
app.Searcher = class Searcher extends Events {
|
||||
static initClass() {
|
||||
CHUNK_SIZE = 20000;
|
||||
app.Searcher = class Searcher extends Events {
|
||||
static CHUNK_SIZE = 20000;
|
||||
|
||||
DEFAULTS = {
|
||||
max_results: app.config.max_results,
|
||||
fuzzy_min_length: 3,
|
||||
};
|
||||
static DEFAULTS = {
|
||||
max_results: app.config.max_results,
|
||||
fuzzy_min_length: 3,
|
||||
};
|
||||
|
||||
SEPARATORS_REGEXP =
|
||||
/#|::|:-|->|\$(?=\w)|\-(?=\w)|\:(?=\w)|\ [\/\-&]\ |:\ |\ /g;
|
||||
EOS_SEPARATORS_REGEXP = /(\w)[\-:]$/;
|
||||
INFO_PARANTHESES_REGEXP = /\ \(\w+?\)$/;
|
||||
EMPTY_PARANTHESES_REGEXP = /\(\)/;
|
||||
EVENT_REGEXP = /\ event$/;
|
||||
DOT_REGEXP = /\.+/g;
|
||||
WHITESPACE_REGEXP = /\s/g;
|
||||
static SEPARATORS_REGEXP =
|
||||
/#|::|:-|->|\$(?=\w)|\-(?=\w)|\:(?=\w)|\ [\/\-&]\ |:\ |\ /g;
|
||||
static EOS_SEPARATORS_REGEXP = /(\w)[\-:]$/;
|
||||
static INFO_PARANTHESES_REGEXP = /\ \(\w+?\)$/;
|
||||
static EMPTY_PARANTHESES_REGEXP = /\(\)/;
|
||||
static EVENT_REGEXP = /\ event$/;
|
||||
static DOT_REGEXP = /\.+/g;
|
||||
static WHITESPACE_REGEXP = /\s/g;
|
||||
|
||||
EMPTY_STRING = "";
|
||||
ELLIPSIS = "...";
|
||||
STRING = "string";
|
||||
static EMPTY_STRING = "";
|
||||
static ELLIPSIS = "...";
|
||||
static STRING = "string";
|
||||
|
||||
static normalizeString(string) {
|
||||
return string
|
||||
.toLowerCase()
|
||||
.replace(Searcher.ELLIPSIS, Searcher.EMPTY_STRING)
|
||||
.replace(Searcher.EVENT_REGEXP, Searcher.EMPTY_STRING)
|
||||
.replace(Searcher.INFO_PARANTHESES_REGEXP, Searcher.EMPTY_STRING)
|
||||
.replace(Searcher.SEPARATORS_REGEXP, SEPARATOR)
|
||||
.replace(Searcher.DOT_REGEXP, SEPARATOR)
|
||||
.replace(Searcher.EMPTY_PARANTHESES_REGEXP, Searcher.EMPTY_STRING)
|
||||
.replace(Searcher.WHITESPACE_REGEXP, Searcher.EMPTY_STRING);
|
||||
}
|
||||
|
||||
static normalizeQuery(string) {
|
||||
string = this.normalizeString(string);
|
||||
return string.replace(Searcher.EOS_SEPARATORS_REGEXP, "$1.");
|
||||
}
|
||||
|
||||
constructor(options) {
|
||||
super();
|
||||
this.options = $.extend({}, Searcher.DEFAULTS, options || {});
|
||||
}
|
||||
|
||||
find(data, attr, q) {
|
||||
this.kill();
|
||||
|
||||
this.data = data;
|
||||
this.attr = attr;
|
||||
this.query = q;
|
||||
this.setup();
|
||||
|
||||
if (this.isValid()) {
|
||||
this.match();
|
||||
} else {
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
|
||||
static normalizeString(string) {
|
||||
return string
|
||||
.toLowerCase()
|
||||
.replace(ELLIPSIS, EMPTY_STRING)
|
||||
.replace(EVENT_REGEXP, EMPTY_STRING)
|
||||
.replace(INFO_PARANTHESES_REGEXP, EMPTY_STRING)
|
||||
.replace(SEPARATORS_REGEXP, SEPARATOR)
|
||||
.replace(DOT_REGEXP, SEPARATOR)
|
||||
.replace(EMPTY_PARANTHESES_REGEXP, EMPTY_STRING)
|
||||
.replace(WHITESPACE_REGEXP, EMPTY_STRING);
|
||||
setup() {
|
||||
query = this.query = this.constructor.normalizeQuery(this.query);
|
||||
queryLength = query.length;
|
||||
this.dataLength = this.data.length;
|
||||
this.matchers = [exactMatch];
|
||||
this.totalResults = 0;
|
||||
this.setupFuzzy();
|
||||
}
|
||||
|
||||
setupFuzzy() {
|
||||
if (queryLength >= this.options.fuzzy_min_length) {
|
||||
fuzzyRegexp = this.queryToFuzzyRegexp(query);
|
||||
this.matchers.push(fuzzyMatch);
|
||||
} else {
|
||||
fuzzyRegexp = null;
|
||||
}
|
||||
}
|
||||
|
||||
static normalizeQuery(string) {
|
||||
string = this.normalizeString(string);
|
||||
return string.replace(EOS_SEPARATORS_REGEXP, "$1.");
|
||||
isValid() {
|
||||
return queryLength > 0 && query !== SEPARATOR;
|
||||
}
|
||||
|
||||
end() {
|
||||
if (!this.totalResults) {
|
||||
this.triggerResults([]);
|
||||
}
|
||||
this.trigger("end");
|
||||
this.free();
|
||||
}
|
||||
|
||||
constructor(options) {
|
||||
super();
|
||||
this.options = $.extend({}, DEFAULTS, options || {});
|
||||
}
|
||||
|
||||
find(data, attr, q) {
|
||||
this.kill();
|
||||
|
||||
this.data = data;
|
||||
this.attr = attr;
|
||||
this.query = q;
|
||||
this.setup();
|
||||
|
||||
if (this.isValid()) {
|
||||
this.match();
|
||||
} else {
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
|
||||
setup() {
|
||||
query = this.query = this.constructor.normalizeQuery(this.query);
|
||||
queryLength = query.length;
|
||||
this.dataLength = this.data.length;
|
||||
this.matchers = [exactMatch];
|
||||
this.totalResults = 0;
|
||||
this.setupFuzzy();
|
||||
}
|
||||
|
||||
setupFuzzy() {
|
||||
if (queryLength >= this.options.fuzzy_min_length) {
|
||||
fuzzyRegexp = this.queryToFuzzyRegexp(query);
|
||||
this.matchers.push(fuzzyMatch);
|
||||
} else {
|
||||
fuzzyRegexp = null;
|
||||
}
|
||||
}
|
||||
|
||||
isValid() {
|
||||
return queryLength > 0 && query !== SEPARATOR;
|
||||
}
|
||||
|
||||
end() {
|
||||
if (!this.totalResults) {
|
||||
this.triggerResults([]);
|
||||
}
|
||||
this.trigger("end");
|
||||
kill() {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
this.free();
|
||||
}
|
||||
}
|
||||
|
||||
kill() {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
this.free();
|
||||
}
|
||||
free() {
|
||||
this.data = null;
|
||||
this.attr = null;
|
||||
this.dataLength = null;
|
||||
this.matchers = null;
|
||||
this.matcher = null;
|
||||
this.query = null;
|
||||
this.totalResults = null;
|
||||
this.scoreMap = null;
|
||||
this.cursor = null;
|
||||
this.timeout = null;
|
||||
}
|
||||
|
||||
match() {
|
||||
if (!this.foundEnough() && (this.matcher = this.matchers.shift())) {
|
||||
this.setupMatcher();
|
||||
this.matchChunks();
|
||||
} else {
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
|
||||
free() {
|
||||
this.data =
|
||||
this.attr =
|
||||
this.dataLength =
|
||||
this.matchers =
|
||||
this.matcher =
|
||||
this.query =
|
||||
this.totalResults =
|
||||
this.scoreMap =
|
||||
this.cursor =
|
||||
this.timeout =
|
||||
null;
|
||||
setupMatcher() {
|
||||
this.cursor = 0;
|
||||
this.scoreMap = new Array(101);
|
||||
}
|
||||
|
||||
matchChunks() {
|
||||
this.matchChunk();
|
||||
|
||||
if (this.cursor === this.dataLength || this.scoredEnough()) {
|
||||
this.delay(() => this.match());
|
||||
this.sendResults();
|
||||
} else {
|
||||
this.delay(() => this.matchChunks());
|
||||
}
|
||||
}
|
||||
|
||||
match() {
|
||||
if (!this.foundEnough() && (this.matcher = this.matchers.shift())) {
|
||||
this.setupMatcher();
|
||||
this.matchChunks();
|
||||
matchChunk() {
|
||||
({ matcher } = this);
|
||||
for (let j = 0, end = this.chunkSize(); j < end; j++) {
|
||||
value = this.data[this.cursor][this.attr];
|
||||
if (value.split) {
|
||||
// string
|
||||
valueLength = value.length;
|
||||
if ((score = matcher())) {
|
||||
this.addResult(this.data[this.cursor], score);
|
||||
}
|
||||
} else {
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
|
||||
setupMatcher() {
|
||||
this.cursor = 0;
|
||||
this.scoreMap = new Array(101);
|
||||
}
|
||||
|
||||
matchChunks() {
|
||||
this.matchChunk();
|
||||
|
||||
if (this.cursor === this.dataLength || this.scoredEnough()) {
|
||||
this.delay(() => this.match());
|
||||
this.sendResults();
|
||||
} else {
|
||||
this.delay(() => this.matchChunks());
|
||||
}
|
||||
}
|
||||
|
||||
matchChunk() {
|
||||
({ matcher } = this);
|
||||
for (
|
||||
let j = 0, end = this.chunkSize(), asc = 0 <= end;
|
||||
asc ? j < end : j > end;
|
||||
asc ? j++ : j--
|
||||
) {
|
||||
value = this.data[this.cursor][this.attr];
|
||||
if (value.split) {
|
||||
// string
|
||||
// array
|
||||
score = 0;
|
||||
for (value of Array.from(this.data[this.cursor][this.attr])) {
|
||||
valueLength = value.length;
|
||||
if ((score = matcher())) {
|
||||
this.addResult(this.data[this.cursor], score);
|
||||
}
|
||||
} else {
|
||||
// array
|
||||
score = 0;
|
||||
for (value of Array.from(this.data[this.cursor][this.attr])) {
|
||||
valueLength = value.length;
|
||||
score = Math.max(score, matcher() || 0);
|
||||
}
|
||||
if (score > 0) {
|
||||
this.addResult(this.data[this.cursor], score);
|
||||
}
|
||||
score = Math.max(score, matcher() || 0);
|
||||
}
|
||||
this.cursor++;
|
||||
}
|
||||
}
|
||||
|
||||
chunkSize() {
|
||||
if (this.cursor + CHUNK_SIZE > this.dataLength) {
|
||||
return this.dataLength % CHUNK_SIZE;
|
||||
} else {
|
||||
return CHUNK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
scoredEnough() {
|
||||
return (
|
||||
(this.scoreMap[100] != null ? this.scoreMap[100].length : undefined) >=
|
||||
this.options.max_results
|
||||
);
|
||||
}
|
||||
|
||||
foundEnough() {
|
||||
return this.totalResults >= this.options.max_results;
|
||||
}
|
||||
|
||||
addResult(object, score) {
|
||||
let name;
|
||||
(
|
||||
this.scoreMap[(name = Math.round(score))] || (this.scoreMap[name] = [])
|
||||
).push(object);
|
||||
this.totalResults++;
|
||||
}
|
||||
|
||||
getResults() {
|
||||
const results = [];
|
||||
for (let j = this.scoreMap.length - 1; j >= 0; j--) {
|
||||
var objects = this.scoreMap[j];
|
||||
if (objects) {
|
||||
results.push.apply(results, objects);
|
||||
if (score > 0) {
|
||||
this.addResult(this.data[this.cursor], score);
|
||||
}
|
||||
}
|
||||
return results.slice(0, this.options.max_results);
|
||||
this.cursor++;
|
||||
}
|
||||
}
|
||||
|
||||
sendResults() {
|
||||
const results = this.getResults();
|
||||
if (results.length) {
|
||||
this.triggerResults(results);
|
||||
chunkSize() {
|
||||
if (this.cursor + Searcher.CHUNK_SIZE > this.dataLength) {
|
||||
return this.dataLength % Searcher.CHUNK_SIZE;
|
||||
} else {
|
||||
return Searcher.CHUNK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
scoredEnough() {
|
||||
return (
|
||||
(this.scoreMap[100] != null ? this.scoreMap[100].length : undefined) >=
|
||||
this.options.max_results
|
||||
);
|
||||
}
|
||||
|
||||
foundEnough() {
|
||||
return this.totalResults >= this.options.max_results;
|
||||
}
|
||||
|
||||
addResult(object, score) {
|
||||
let name;
|
||||
(
|
||||
this.scoreMap[(name = Math.round(score))] || (this.scoreMap[name] = [])
|
||||
).push(object);
|
||||
this.totalResults++;
|
||||
}
|
||||
|
||||
getResults() {
|
||||
const results = [];
|
||||
for (let j = this.scoreMap.length - 1; j >= 0; j--) {
|
||||
var objects = this.scoreMap[j];
|
||||
if (objects) {
|
||||
results.push.apply(results, objects);
|
||||
}
|
||||
}
|
||||
return results.slice(0, this.options.max_results);
|
||||
}
|
||||
|
||||
triggerResults(results) {
|
||||
this.trigger("results", results);
|
||||
sendResults() {
|
||||
const results = this.getResults();
|
||||
if (results.length) {
|
||||
this.triggerResults(results);
|
||||
}
|
||||
}
|
||||
|
||||
delay(fn) {
|
||||
return (this.timeout = setTimeout(fn, 1));
|
||||
}
|
||||
triggerResults(results) {
|
||||
this.trigger("results", results);
|
||||
}
|
||||
|
||||
queryToFuzzyRegexp(string) {
|
||||
const chars = string.split("");
|
||||
for (i = 0; i < chars.length; i++) {
|
||||
var char = chars[i];
|
||||
chars[i] = $.escapeRegexp(char);
|
||||
}
|
||||
return new RegExp(chars.join(".*?")); // abc -> /a.*?b.*?c.*?/
|
||||
delay(fn) {
|
||||
return (this.timeout = setTimeout(fn, 1));
|
||||
}
|
||||
|
||||
queryToFuzzyRegexp(string) {
|
||||
const chars = string.split("");
|
||||
for (i = 0; i < chars.length; i++) {
|
||||
var char = chars[i];
|
||||
chars[i] = $.escapeRegexp(char);
|
||||
}
|
||||
};
|
||||
app.Searcher.initClass();
|
||||
return app.Searcher;
|
||||
})();
|
||||
return new RegExp(chars.join(".*?")); // abc -> /a.*?b.*?c.*?/
|
||||
}
|
||||
};
|
||||
|
||||
app.SynchronousSearcher = class SynchronousSearcher extends app.Searcher {
|
||||
match() {
|
||||
|
|
Loading…
Reference in a new issue