tokenize = (query, {
not = "-",
delimiter = ":",
quotes = ['"', "'", "`"],
} = {}) => {
const fillKeys = (keys, value) => Object.fromEntries(keys.map(k => [k, value]));
const prefixes = {
[not]: ctx => { ctx.not = !ctx.not },
};
const modifiers = {
...fillKeys(quotes, (ctx, char) => { ctx.quote = char }),
[delimiter]: (ctx, char) => { ctx.keys.push(ctx.term); ctx.term = "" },
};
let ctx, quote;
const reset = () => (ctx = ({ term: "", keys: [], not: false, quote: null }));
reset();
const terms = [];
const commit = ({quote, ...ctx}) => {
if(ctx.term.length) terms.push(ctx);
reset();
};
for(const c of query) {
if(ctx.quote === c) ctx.quote = null;
else if(ctx.quote === null && c === " ") commit(ctx);
else if(ctx.quote === null && !ctx.term.length && prefixes[c]) prefixes[c](ctx, c);
else if(ctx.quote === null && modifiers[c]) modifiers[c](ctx, c);
else ctx.term += c;
}
commit(ctx);
return terms;
}