refined-text-search
Version:
Tokenize a search query with refined options (like Google's) and match against a target
47 lines • 1.72 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.match = exports.tokenizeClause = exports.tokenize = void 0;
const pattern = /(=|-)?("[^"]*"|[^\s]+)/g;
function tokenize(query) {
query = query.toLowerCase().trim();
const orClauses = query.split(/ or | \| /);
if (orClauses.length === 1) {
return tokenizeClause(orClauses[0]);
}
return [{ or: true, children: orClauses.map(tokenizeClause) }];
}
exports.tokenize = tokenize;
function tokenizeClause(query) {
const tokens = [];
let matched;
while ((matched = pattern.exec(query))) {
const prefix = matched[1];
let term = matched[2];
term = term.replace(/(^"|"$)/g, '');
const exclude = prefix === '-' ? true : undefined;
const exact = prefix === '=' ? true : undefined;
tokens.push(Object.assign(Object.assign({ term }, (exclude ? { exclude } : {})), (exact ? { exact } : {})));
}
tokens.sort((a, b) => (a.exclude === b.exclude ? 0 : a.exclude ? -1 : 1));
return tokens;
}
exports.tokenizeClause = tokenizeClause;
function match(tokens, text) {
text = text.replace(/\s+/g, ' ').trim().toLowerCase();
for (let i = 0; i !== tokens.length; i++) {
const token = tokens[i];
if ('or' in token) {
return token.children.some((childTokens) => match(childTokens, text));
}
const textMatch = token.exact ? text === token.term : text.indexOf(token.term) !== -1;
if (token.exclude && textMatch) {
return false;
}
if (!token.exclude && !textMatch) {
return false;
}
}
return true;
}
exports.match = match;
//# sourceMappingURL=index.js.map