search-query-parser
Advanced tools
Comparing version 1.2.0 to 1.3.0
@@ -18,6 +18,2 @@ /*! | ||
// Regularize white spacing | ||
// Make in-between white spaces a unique space | ||
string = string.trim().replace(/\s+/g, ' '); | ||
// When a simple string, return it | ||
@@ -34,12 +30,15 @@ if (-1 === string.indexOf(':')) { | ||
// 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; | ||
var match; | ||
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 | ||
@@ -60,3 +59,14 @@ val = val.replace(/^\"|\"$|^\'|\'$/g, ''); | ||
}); | ||
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 | ||
}); | ||
} | ||
@@ -69,13 +79,11 @@ } | ||
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 | ||
@@ -95,2 +103,3 @@ options.keywords = options.keywords || []; | ||
} | ||
// Check if the key is a registered range | ||
@@ -101,3 +110,10 @@ options.ranges = options.ranges || []; | ||
if (isKeyword) { | ||
var value = term.slice(sepIdx + 1); | ||
query.offsets.push({ | ||
keyword: key, | ||
value: term.value, | ||
offsetStart: isExclusion ? term.offsetStart + 1 : term.offsetStart, | ||
offsetEnd: term.offsetEnd | ||
}); | ||
var value = term.value; | ||
// When value is a thing | ||
@@ -183,3 +199,5 @@ if (value.length) { | ||
else if (isRange) { | ||
var value = term.slice(sepIdx + 1); | ||
query.offsets.push(term); | ||
var value = term.value; | ||
// Range are separated with a dash | ||
@@ -206,3 +224,10 @@ var rangeValues = value.split('-'); | ||
// We add it as pure text | ||
query.text.push(term); | ||
var text = term.keyword + ':' + term.value; | ||
query.text.push(text); | ||
query.offsets.push({ | ||
text: text, | ||
offsetStart: term.offsetStart, | ||
offsetEnd: term.offsetEnd | ||
}); | ||
} | ||
@@ -209,0 +234,0 @@ } |
{ | ||
"name": "search-query-parser", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "Parser for advanced search query syntax", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -23,3 +23,9 @@ # Search Query Syntax Parser | ||
}, | ||
text: 'photos' | ||
text: 'photos', | ||
offsets: | ||
[ { keyword: 'from', value: 'hi@retrace.io,foo@gmail.com', offsetStart: 0, offsetEnd: 32 }, | ||
{ keyword: 'to', value: 'me', offsetStart: 33, offsetEnd: 38 }, | ||
{ keyword: 'subject', value: 'vacations', offsetStart: 39, offsetEnd: 56 }, | ||
{ keyword: 'date', value: '1/10/2013-15/04/2014', offsetStart: 57, offsetEnd: 82 }, | ||
{ text: 'photos', offsetStart: 83, offsetEnd: 89 } ] | ||
} | ||
@@ -26,0 +32,0 @@ ``` |
278
test/test.js
@@ -26,2 +26,8 @@ var assert = require('assert') | ||
parsedSearchQuery.should.not.have.property('text'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'from', | ||
value: 'jul@foo.com', | ||
offsetStart: 0, | ||
offsetEnd: 16 | ||
}]); | ||
}); | ||
@@ -38,6 +44,46 @@ | ||
parsedSearchQuery.should.have.property('text', 'hey buddy!'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'from', | ||
value: 'jul@foo.com', | ||
offsetStart: 0, | ||
offsetEnd: 16 | ||
}, { | ||
text: 'hey', | ||
offsetStart: 17, | ||
offsetEnd: 20 | ||
}, { | ||
text: 'buddy!', | ||
offsetStart: 21, | ||
offsetEnd: 27 | ||
}]); | ||
}); | ||
it('should parse a single keyword with free text before it', function () { | ||
it('should ignore keywords that are not specified', function() { | ||
var searchQuery = 'test another other:jul@foo.com'; | ||
var options = { | ||
keywords: ['from'] | ||
}; | ||
var parsedSearchQuery = searchquery.parse(searchQuery, options); | ||
parsedSearchQuery.should.be.an.Object; | ||
parsedSearchQuery.should.have.not.have.property('other'); | ||
parsedSearchQuery.should.have.property('text', 'test another other:jul@foo.com'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
text: 'test', | ||
offsetStart: 0, | ||
offsetEnd: 4 | ||
}, { | ||
text: 'another', | ||
offsetStart: 5, | ||
offsetEnd: 12 | ||
}, { | ||
text: 'other:jul@foo.com', | ||
offsetStart: 13, | ||
offsetEnd: 30 | ||
}]); | ||
}); | ||
it('should parse a single keyword with free text before it', function() { | ||
var searchQuery = 'hey you! from:jul@foo.com'; | ||
@@ -50,2 +96,16 @@ var options = {keywords: ['from']}; | ||
parsedSearchQuery.should.have.property('text', 'hey you!'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
text: 'hey', | ||
offsetStart: 0, | ||
offsetEnd: 3 | ||
}, { | ||
text: 'you!', | ||
offsetStart: 4, | ||
offsetEnd: 8 | ||
}, { | ||
keyword: 'from', | ||
value: 'jul@foo.com', | ||
offsetStart: 9, | ||
offsetEnd: 25 | ||
}]); | ||
}); | ||
@@ -62,2 +122,20 @@ | ||
parsedSearchQuery.should.have.property('text', 'hey you! pouet'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
text: 'hey', | ||
offsetStart: 0, | ||
offsetEnd: 3 | ||
}, { | ||
text: 'you!', | ||
offsetStart: 4, | ||
offsetEnd: 8 | ||
}, { | ||
keyword: 'from', | ||
value: 'jul@foo.com', | ||
offsetStart: 9, | ||
offsetEnd: 25 | ||
}, { | ||
text: 'pouet', | ||
offsetStart: 26, | ||
offsetEnd: 31 | ||
}]); | ||
}); | ||
@@ -75,2 +153,20 @@ | ||
parsedSearchQuery.should.have.property('text', 'hey you! pouet'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
text: 'hey', | ||
offsetStart: 3, | ||
offsetEnd: 6 | ||
}, { | ||
text: 'you!', | ||
offsetStart: 11, | ||
offsetEnd: 15 | ||
}, { | ||
keyword: 'from', | ||
value: 'jul@foo.com', | ||
offsetStart: 16, | ||
offsetEnd: 32 | ||
}, { | ||
text: 'pouet', | ||
offsetStart: 35, | ||
offsetEnd: 40 | ||
}]); | ||
}); | ||
@@ -88,2 +184,33 @@ | ||
parsedSearchQuery.should.have.property('text', 'hey, so what\'s up gents'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
text: 'hey,', | ||
offsetStart: 0, | ||
offsetEnd: 4 | ||
}, { | ||
keyword: 'from', | ||
value: 'jul@foo.com', | ||
offsetStart: 5, | ||
offsetEnd: 21 | ||
}, { | ||
keyword: 'to', | ||
value: 'bar@hey.ya', | ||
offsetStart: 22, | ||
offsetEnd: 35 | ||
}, { | ||
text: 'so', | ||
offsetStart: 36, | ||
offsetEnd: 38 | ||
}, { | ||
text: 'what\'s', | ||
offsetStart: 39, | ||
offsetEnd: 45 | ||
}, { | ||
text: 'up', | ||
offsetStart: 46, | ||
offsetEnd: 48 | ||
}, { | ||
text: 'gents', | ||
offsetStart: 49, | ||
offsetEnd: 54 | ||
}]); | ||
}); | ||
@@ -104,2 +231,17 @@ | ||
parsedSearchQuery.from.should.containEql('bar@hey.ya'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'from', | ||
value: 'jul@foo.com', | ||
offsetStart: 0, | ||
offsetEnd: 16 | ||
}, { | ||
keyword: 'from', | ||
value: 'bar@hey.ya', | ||
offsetStart: 17, | ||
offsetEnd: 32 | ||
}, { | ||
text: 'vaccationessss', | ||
offsetStart: 33, | ||
offsetEnd: 47 | ||
}]); | ||
}); | ||
@@ -119,2 +261,8 @@ | ||
parsedSearchQuery.from.should.containEql('bar@hey.ya'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'from', | ||
value: 'jul@foo.com,bar@hey.ya', | ||
offsetStart: 0, | ||
offsetEnd: 27 | ||
}]); | ||
}); | ||
@@ -137,2 +285,17 @@ | ||
parsedSearchQuery.from.should.containEql('d@e.f'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'from', | ||
value: 'jul@foo.com,bar@hey.ya', | ||
offsetStart: 0, | ||
offsetEnd: 27 | ||
}, { | ||
keyword: 'from', | ||
value: 'a@b.c,d@e.f', | ||
offsetStart: 28, | ||
offsetEnd: 44 | ||
}, { | ||
text: 'ouch!#', | ||
offsetStart: 45, | ||
offsetEnd: 51 | ||
}]); | ||
}); | ||
@@ -151,2 +314,12 @@ | ||
parsedSearchQuery.date.from.should.containEql('12/12/2012'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'date', | ||
value: '12/12/2012', | ||
offsetStart: 0, | ||
offsetEnd: 15 | ||
}, { | ||
text: 'ahaha', | ||
offsetStart: 16, | ||
offsetEnd: 21 | ||
}]); | ||
}); | ||
@@ -165,2 +338,12 @@ | ||
parsedSearchQuery.date.to.should.containEql('01/01/2014'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'date', | ||
value: '12/12/2012-01/01/2014', | ||
offsetStart: 0, | ||
offsetEnd: 26 | ||
}, { | ||
text: 'ahaha', | ||
offsetStart: 27, | ||
offsetEnd: 32 | ||
}]); | ||
}); | ||
@@ -212,2 +395,44 @@ | ||
parsedSearchQuery.to.should.containEql('toto@hey.co'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'date', | ||
value: '12/12/2012-01/01/2014', | ||
offsetStart: 3, | ||
offsetEnd: 29 | ||
}, { | ||
text: 'ahaha', | ||
offsetStart: 30, | ||
offsetEnd: 35 | ||
}, { | ||
keyword: 'from', | ||
value: 'jul@foo.com,bar@hey.ya', | ||
offsetStart: 36, | ||
offsetEnd: 63 | ||
}, { | ||
keyword: 'from', | ||
value: 'a@b.c,d@e.f', | ||
offsetStart: 64, | ||
offsetEnd: 80 | ||
}, { | ||
text: 'ouch!#', | ||
offsetStart: 81, | ||
offsetEnd: 87 | ||
}, { | ||
keyword: 'to', | ||
value: 'me@me.com', | ||
offsetStart: 90, | ||
offsetEnd: 102 | ||
}, { | ||
keyword: 'to', | ||
value: 'toto@hey.co', | ||
offsetStart: 103, | ||
offsetEnd: 117 | ||
}, { | ||
text: 'about', | ||
offsetStart: 118, | ||
offsetEnd: 123 | ||
}, { | ||
text: 'that', | ||
offsetStart: 124, | ||
offsetEnd: 128 | ||
}]); | ||
}); | ||
@@ -224,2 +449,13 @@ | ||
parsedSearchQuery.should.have.property('description', 'Banana Sandwiche'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'name', | ||
value: 'Bob Saget', | ||
offsetStart: 0, | ||
offsetEnd: 16 | ||
}, { | ||
keyword: 'description', | ||
value: 'Banana Sandwiche', | ||
offsetStart: 17, | ||
offsetEnd: 47 | ||
}]); | ||
}); | ||
@@ -236,2 +472,13 @@ | ||
parsedSearchQuery.should.have.property('case2', 'This "is" \'a\' test'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'case1', | ||
value: 'This "is" \'a\' test', | ||
offsetStart: 0, | ||
offsetEnd: 28 | ||
}, { | ||
keyword: 'case2', | ||
value: 'This "is" \'a\' test', | ||
offsetStart: 29, | ||
offsetEnd: 57 | ||
}]); | ||
}); | ||
@@ -249,2 +496,8 @@ | ||
parsedSearchQuery.should.not.have.property('text'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'from', | ||
value: 'jul@foo.com', | ||
offsetStart: 1, | ||
offsetEnd: 17 | ||
}]); | ||
}); | ||
@@ -262,2 +515,8 @@ | ||
parsedSearchQuery.should.not.have.property('text'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'from', | ||
value: 'jul@foo.com,mar@foo.com', | ||
offsetStart: 1, | ||
offsetEnd: 29 | ||
}]); | ||
}); | ||
@@ -267,3 +526,5 @@ | ||
var searchQuery = '-from:jul@foo.com,mar@foo.com -from:jan@foo.com'; | ||
var options = {keywords: ['from']}; | ||
var options = { | ||
keywords: ['from'] | ||
}; | ||
var parsedSearchQuery = searchquery.parse(searchQuery, options); | ||
@@ -277,3 +538,14 @@ | ||
parsedSearchQuery.should.not.have.property('text'); | ||
parsedSearchQuery.should.have.property('offsets', [{ | ||
keyword: 'from', | ||
value: 'jul@foo.com,mar@foo.com', | ||
offsetStart: 1, | ||
offsetEnd: 29 | ||
}, { | ||
keyword: 'from', | ||
value: 'jan@foo.com', | ||
offsetStart: 31, | ||
offsetEnd: 47 | ||
}]); | ||
}); | ||
}); | ||
}); |
159910
5723
118
12