Skip to content

Commit

Permalink
Add option to customize negate prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan-Roger authored and Ivan ROGER committed Mar 9, 2023
1 parent 8158d09 commit 7fcd56f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 15 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ var searchQueryObj = searchQuery.parse(query, options);
```

You can configure what keywords and ranges the parser should accept with the options argument.
It accepts 5 values:
It accepts 6 values:
* `keywords`, that can be separated by commas (,). Accepts an array of strings.
* `ranges`, that can be separated by a hyphen (-). Accepts an array of strings.
* `tokenize`, that controls the behaviour of text search terms. If set to `true`, non-keyword text terms are returned as an array of strings where each term in the array is a whitespace-separated word, or a multi-word term surrounded by single- or double-quotes.
* `alwaysArray`, a boolean that controls the behaviour of the returned query. If set to `true`, all matched keywords would always be arrays instead of strings. If set to `false` they will be strings if matched a single value. Defaults to `false`.
* `offsets`, a boolean that controls the behaviour of the returned query. If set to `true`, the query will contain the offsets object. If set to `false`, the query will not contain the offsets object. Defaults to `true`.
* `negatePrefix`, a string that controls the behaviour of the returned query. It defines what prefix is used to mark a term as excluded. Defaults to `'-'`.

If no keywords or ranges are specified, or if none are present in the given search query, then `searchQuery.parse` will return a string if `tokenize` is false, or an array of strings under the key `text` if `tokenize` is true.

Expand Down
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface SearchParserOptions {
keywords?: string[];
ranges?: string[];
alwaysArray?: boolean;
negatePrefix?: string;
}

export interface ISearchParserDictionary {
Expand Down
33 changes: 19 additions & 14 deletions lib/search-query-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ exports.parse = function (string, options) {

// Set a default options object when none is provided
if (!options) {
options = {offsets: true};
options = {offsets: true, negatePrefix: '-'};
} else {
// If options offsets was't passed, set it to true
options.offsets = (typeof options.offsets === 'undefined' ? true : options.offsets)
// If options negatePrefix was't passed, set it to '-'
options.negatePrefix = (typeof options.negatePrefix === 'undefined' ? '-' : options.negatePrefix)
}

if (!string) {
Expand Down Expand Up @@ -69,9 +71,9 @@ exports.parse = function (string, options) {
});
} else {
var isExcludedTerm = false;
if (term[0] === '-') {
if (term.startsWith(options.negatePrefix)) {
isExcludedTerm = true;
term = term.slice(1);
term = term.slice(options.negatePrefix.length);
}

// Strip surrounding quotes
Expand Down Expand Up @@ -132,15 +134,15 @@ exports.parse = function (string, options) {
options.keywords = options.keywords || [];
var isKeyword = false;
var isExclusion = false;
if (!/^-/.test(key)) {
isKeyword = !(-1 === options.keywords.indexOf(key));
} else if (key[0] === '-') {
var _key = key.slice(1);
isKeyword = !(-1 === options.keywords.indexOf(_key))
if (isKeyword) {
key = _key;
isExclusion = true;
}
if (key.startsWith(options.negatePrefix)) {
var _key = key.slice(options.negatePrefix.length);
isKeyword = !(-1 === options.keywords.indexOf(_key))
if (isKeyword) {
key = _key;
isExclusion = true;
}
} else {
isKeyword = !(-1 === options.keywords.indexOf(key));
}

// Check if the key is a registered range
Expand Down Expand Up @@ -314,7 +316,10 @@ exports.stringify = function (queryObject, options, prefix) {

// Set a default options object when none is provided
if (!options) {
options = {offsets: true};
options = {offsets: true, negatePrefix: '-'};
} else {
// If options negatePrefix was't passed, set it to '-'
options.negatePrefix = (typeof options.negatePrefix === 'undefined' ? '-' : options.negatePrefix)
}

// If the query object is falsy we can just return an empty string
Expand Down Expand Up @@ -414,7 +419,7 @@ exports.stringify = function (queryObject, options, prefix) {
// Exclude
if (queryObject.exclude) {
if (Object.keys(queryObject.exclude).length > 0) {
parts.push(exports.stringify(queryObject.exclude, options, '-'));
parts.push(exports.stringify(queryObject.exclude, options, options.negatePrefix));
}
}

Expand Down
27 changes: 27 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ describe('Search query syntax parser', function () {
parsedAfterStringifySearchQuery.should.be.eql(parsedSearchQuery);
});

it('should return a tokenized string with custom negation prefix', function () {
var searchQuery = "fancy !pyjama !wear";
var options = { tokenize: true, negatePrefix: '!' };
var parsedSearchQuery = searchquery.parse(searchQuery, options);

parsedSearchQuery.should.be.an.Object;
parsedSearchQuery.should.have.property('text', ['fancy']);
parsedSearchQuery.should.have.property('exclude', {text: ['pyjama', 'wear']});

var parsedAfterStringifySearchQuery = searchquery.parse(searchquery.stringify(parsedSearchQuery, options), options);
parsedAfterStringifySearchQuery.offsets = undefined;
parsedSearchQuery.offsets = undefined;
parsedAfterStringifySearchQuery.should.be.eql(parsedSearchQuery);
});

it('should return a tokenized string with negation of single-quoted terms', function () {
var searchQuery = "fancy -'pyjama -wear'";
var options = { tokenize: true };
Expand Down Expand Up @@ -788,4 +803,16 @@ describe('Search query syntax parser', function () {
parsedSearchQuery.offsets = undefined;
parsedAfterStringifySearchQuery.should.be.eql(parsedSearchQuery);
});

it('should stringify properly with default negate prefix', function () {
var searchQueryObject = {
text: [ 'fancy' ],
exclude: { text: [ 'pyjama', 'wear' ] }
};
var options = { tokenize: true };
stringifiedSearchQuery = searchquery.stringify(searchQueryObject, options);

stringifiedSearchQuery.should.be.a.string;
stringifiedSearchQuery.should.be.eql('fancy -pyjama -wear');
});
});

0 comments on commit 7fcd56f

Please sign in to comment.