You've already forked search-query-parser
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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user