1
0

Return the character offsets of parsed search parts. The use case is that browser code using the library might want to track the cursor position (eg in an HTML <input> element) to understand which part of the search query the user is editing. It could then show an editor specific to that keyboard, such as a calendar picker, and then splice in the edited value back into the search string.

This commit is contained in:
Brad Vogel
2016-10-28 12:58:10 -07:00
parent 180a449c5e
commit 09a1110f40
3 changed files with 293 additions and 25 deletions

View File

@@ -15,10 +15,6 @@ exports.parse = function (string, options) {
string = '';
}
// Regularize white spacing
// Make in-between white spaces a unique space
string = string.trim().replace(/\s+/g, ' ');
// When a simple string, return it
if (-1 === string.indexOf(':')) {
return string;
@@ -30,16 +26,18 @@ exports.parse = function (string, options) {
// Otherwise parse the advanced query syntax
else {
// Our object to store the query object
var query = {text: []};
var query = {text: [], offsets: []};
var exclusion = {};
var terms = [];
// Get a list of search terms respecting single and double quotes
var terms = string.match(/(\S+:'(?:[^'\\]|\\.)*')|(\S+:"(?:[^"\\]|\\.)*")|\S+|\S+:\S+/g);
for (var i = 0; i < terms.length; i++) {
var sepIndex = terms[i].indexOf(':');
if(sepIndex !== -1) {
var split = terms[i].split(':'),
key = terms[i].slice(0, sepIndex),
val = terms[i].slice(sepIndex + 1);
var regex = /(\S+:'(?:[^'\\]|\\.)*')|(\S+:"(?:[^"\\]|\\.)*")|\S+|\S+:\S+/g;
while ((match = regex.exec(string)) !== null) {
var term = match[0];
var sepIndex = term.indexOf(':');
if (sepIndex !== -1) {
var split = term.split(':'),
key = term.slice(0, sepIndex),
val = term.slice(sepIndex + 1);
// Strip surrounding quotes
val = val.replace(/^\"|\"$|^\'|\'$/g, '');
// Strip backslashes respecting escapes
@@ -55,24 +53,34 @@ exports.parse = function (string, options) {
return n1;
}
});
terms[i] = key + ':' + val;
terms.push({
keyword: key,
value: val,
offsetStart: match.index,
offsetEnd: match.index + term.length
});
} else {
terms.push({
text: term,
offsetStart: match.index,
offsetEnd: match.index + term.length
});
}
}
// Reverse to ensure proper order when pop()'ing.
terms.reverse();
// For each search term
var term;
while (term = terms.pop()) {
// Advanced search terms syntax has key and value
// separated with a colon
var sepIdx = term.indexOf(':');
// When just a simple term
if (-1 === sepIdx) {
if (term.text) {
// We add it as pure text
query.text.push(term);
query.text.push(term.text);
query.offsets.push(term);
}
// We got an advanced search syntax
else {
var key = term.slice(0, sepIdx);
var key = term.keyword;
// Check if the key is a registered keyword
options.keywords = options.keywords || [];
var isKeyword = false;
@@ -87,12 +95,20 @@ exports.parse = function (string, options) {
isExclusion = true;
}
}
query.offsets.push({
keyword: key,
value: term.value,
offsetStart: isExclusion ? term.offsetStart + 1 : term.offsetStart,
offsetEnd: term.offsetEnd
});
// Check if the key is a registered range
options.ranges = options.ranges || [];
var isRange = !(-1 === options.ranges.indexOf(key));
// When the key matches a keyword
if (isKeyword) {
var value = term.slice(sepIdx + 1);
var value = term.value;
// When value is a thing
if (value.length) {
// Get an array of values when several are there
@@ -173,7 +189,7 @@ exports.parse = function (string, options) {
}
// The key allows a range
else if (isRange) {
var value = term.slice(sepIdx + 1);
var value = term.value;
// Range are separated with a dash
var rangeValues = value.split('-');
// When both end of the range are specified
@@ -195,7 +211,7 @@ exports.parse = function (string, options) {
}
else {
// We add it as pure text
query.text.push(term);
query.text.push(term.text);
}
}
}