ss-search
Version:
The most basic, yet powerful text search.
97 lines (94 loc) • 4.19 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
convertToSearchableStrings: () => convertToSearchableStrings,
getScore: () => getScore,
indexDocuments: () => indexDocuments,
normalize: () => normalize,
search: () => search,
tokenize: () => tokenize
});
module.exports = __toCommonJS(index_exports);
// src/lib/ss-search.ts
var import_lodash_es = require("lodash-es");
var normalize = /* @__PURE__ */ __name((text) => (0, import_lodash_es.deburr)(text).replace(/[\u0300-\u036f]/g, "").toLocaleLowerCase().trim(), "normalize");
var tokenize = /* @__PURE__ */ __name((searchText) => normalize((0, import_lodash_es.escapeRegExp)(searchText)).match(/[\p{L}\d]+/gimu) || [], "tokenize");
var convertToSearchableStrings = (0, import_lodash_es.memoize)((elements, searchableKeys, _cacheKey) => {
if (!elements || elements.length === 0 || !searchableKeys || searchableKeys.length === 0) {
return [];
}
const arraySelectorRegex = /\[(.*)]/;
return elements.map((element) => searchableKeys.map((key) => {
const value = (0, import_lodash_es.get)(element, key.replace(arraySelectorRegex, ""));
if (value === null || value === void 0 || typeof value === "function") {
return "";
}
const arraySelector = (0, import_lodash_es.get)(arraySelectorRegex.exec(key), "1");
if (arraySelector) {
return value.map((x) => (0, import_lodash_es.get)(x, arraySelector));
}
if (Array.isArray(value) || typeof value === "object") {
return JSON.stringify(value);
}
return value;
}).reduce((a, b) => a + b, "")).map((x) => normalize(x));
}, (elements, _, cacheKey) => cacheKey ?? elements);
var indexDocuments = convertToSearchableStrings;
var getScore = /* @__PURE__ */ __name((matchesAllSearchWords, searchWords, searchableDataString) => {
if (!matchesAllSearchWords) {
return 0;
}
const searchableDataStringWithoutNonWordCharacters = searchableDataString.replace(/[^\p{L}\d]+/gimu, "");
const remainingTextAfterRemovingSearchWords = searchWords.sort((a, b) => b.length - a.length).reduce((remainingText, searchWord) => remainingText.replace(new RegExp(searchWord, "gm"), ""), searchableDataStringWithoutNonWordCharacters);
return (0, import_lodash_es.round)(1 - remainingTextAfterRemovingSearchWords.length / searchableDataStringWithoutNonWordCharacters.length, 4);
}, "getScore");
function search(elements, searchableKeys, searchText, options) {
const searchWords = tokenize(searchText);
const searchableDataStrings = convertToSearchableStrings(elements, searchableKeys, options?.cacheKey);
const results = [];
for (let i = 0; i < searchableDataStrings.length; i++) {
const x = searchableDataStrings[i];
const matchesAllSearchWords = searchWords.every((searchWord) => x.includes(searchWord));
if (options?.withScore) {
const score = getScore(matchesAllSearchWords, searchWords, x);
results.push({
element: elements[i],
score
});
continue;
}
if (matchesAllSearchWords) {
results.push(elements[i]);
}
}
return results;
}
__name(search, "search");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
convertToSearchableStrings,
getScore,
indexDocuments,
normalize,
search,
tokenize
});
;