summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6')
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6178
1 files changed, 26 insertions, 152 deletions
diff --git a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6
index 57c0e8fc359..14ca78e139b 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6
+++ b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6
@@ -1,165 +1,39 @@
(() => {
class FilteredSearchTokenizer {
- static parseToken(input) {
- const colonIndex = input.indexOf(':');
- let tokenKey;
- let tokenValue;
- let tokenSymbol;
-
- if (colonIndex !== -1) {
- tokenKey = input.slice(0, colonIndex).toLowerCase();
- tokenValue = input.slice(colonIndex + 1);
- tokenSymbol = tokenValue[0];
- }
-
- return {
- tokenKey,
- tokenValue,
- tokenSymbol,
- };
- }
-
- static getLastTokenObject(input) {
- const token = FilteredSearchTokenizer.getLastToken(input);
- const colonIndex = token.indexOf(':');
-
- const key = colonIndex !== -1 ? token.slice(0, colonIndex) : '';
- const value = colonIndex !== -1 ? token.slice(colonIndex) : token;
-
- return {
- key,
- value,
- };
- }
-
- static getLastToken(input) {
- let completeToken = false;
- let completeQuotation = true;
- let lastQuotation = '';
- let i = input.length;
-
- const doubleQuote = '"';
- const singleQuote = '\'';
- while (!completeToken && i >= 0) {
- const isDoubleQuote = input[i] === doubleQuote;
- const isSingleQuote = input[i] === singleQuote;
-
- // If the second quotation is found
- if ((lastQuotation === doubleQuote && isDoubleQuote) ||
- (lastQuotation === singleQuote && isSingleQuote)) {
- completeQuotation = true;
- }
-
- // Save the first quotation
- if ((isDoubleQuote && lastQuotation === '') ||
- (isSingleQuote && lastQuotation === '')) {
- lastQuotation = input[i];
- completeQuotation = false;
- }
-
- if (completeQuotation && input[i] === ' ') {
- completeToken = true;
- } else {
- i -= 1;
- }
- }
-
- // Adjust by 1 because of empty space
- return input.slice(i + 1);
- }
-
static processTokens(input) {
+ const tokenRegex = /(\w+):([~%@]?)(?:"(.*?)"|'(.*?)'|(\S+))/g;
const tokens = [];
- let searchToken = '';
- let lastToken = '';
-
- const inputs = input.split(' ');
- let searchTerms = '';
- let lastQuotation = '';
- let incompleteToken = false;
-
- // Iterate through each word (broken up by spaces)
- inputs.forEach((i) => {
- if (incompleteToken) {
- // Continue previous token as it had an escaped
- // quote in the beginning
- const prevToken = tokens.last();
- prevToken.value += ` ${i}`;
-
- // Remove last quotation from the value
- const lastQuotationRegex = new RegExp(lastQuotation, 'g');
- prevToken.value = prevToken.value.replace(lastQuotationRegex, '');
- tokens[tokens.length - 1] = prevToken;
-
- // Check to see if this quotation completes the token value
- if (i.indexOf(lastQuotation) !== -1) {
- lastToken = tokens.last();
- incompleteToken = !incompleteToken;
- }
-
- return;
- }
-
- const colonIndex = i.indexOf(':');
-
- if (colonIndex !== -1) {
- const { tokenKey, tokenValue, tokenSymbol } = gl.FilteredSearchTokenizer.parseToken(i);
-
- const keyMatch = gl.FilteredSearchTokenKeys.searchByKey(tokenKey);
- const symbolMatch = gl.FilteredSearchTokenKeys.searchBySymbol(tokenSymbol);
-
- const doubleQuoteOccurrences = tokenValue.split('"').length - 1;
- const singleQuoteOccurrences = tokenValue.split('\'').length - 1;
-
- const doubleQuoteIndex = tokenValue.indexOf('"');
- const singleQuoteIndex = tokenValue.indexOf('\'');
-
- const doubleQuoteExist = doubleQuoteIndex !== -1;
- const singleQuoteExist = singleQuoteIndex !== -1;
-
- const doubleQuoteExistOnly = doubleQuoteExist && !singleQuoteExist;
- const doubleQuoteIsBeforeSingleQuote =
- doubleQuoteExist && singleQuoteExist && doubleQuoteIndex < singleQuoteIndex;
-
- const singleQuoteExistOnly = singleQuoteExist && !doubleQuoteExist;
- const singleQuoteIsBeforeDoubleQuote =
- doubleQuoteExist && singleQuoteExist && singleQuoteIndex < doubleQuoteIndex;
-
- if ((doubleQuoteExistOnly || doubleQuoteIsBeforeSingleQuote)
- && doubleQuoteOccurrences % 2 !== 0) {
- // " is found and is in front of ' (if any)
- lastQuotation = '"';
- incompleteToken = true;
- } else if ((singleQuoteExistOnly || singleQuoteIsBeforeDoubleQuote)
- && singleQuoteOccurrences % 2 !== 0) {
- // ' is found and is in front of " (if any)
- lastQuotation = '\'';
- incompleteToken = true;
- }
-
- if (keyMatch && tokenValue.length > 0) {
- tokens.push({
- key: keyMatch.key,
- value: tokenValue,
- wildcard: !symbolMatch,
- });
- lastToken = tokens.last();
-
- return;
- }
+ let lastToken = null;
+ const searchToken = input.replace(tokenRegex, (match, key, symbol, v1, v2, v3) => {
+ let tokenValue = v1 || v2 || v3;
+ let tokenSymbol = symbol;
+
+ if (tokenValue === '~' || tokenValue === '%' || tokenValue === '@') {
+ tokenSymbol = tokenValue;
+ tokenValue = '';
}
- // Add space for next term
- searchTerms += `${i} `;
- lastToken = i;
- }, this);
-
- searchToken = searchTerms.trim();
+ tokens.push({
+ key,
+ value: tokenValue || '',
+ symbol: tokenSymbol || '',
+ });
+ return '';
+ }).replace(/\s{2,}/g, ' ').trim() || '';
+
+ if (tokens.length > 0) {
+ const last = tokens[tokens.length - 1];
+ const lastString = `${last.key}:${last.symbol}${last.value}`;
+ lastToken = input.lastIndexOf(lastString) ===
+ input.length - lastString.length ? last : searchToken;
+ } else {
+ lastToken = searchToken;
+ }
return {
tokens,
- searchToken,
lastToken,
+ searchToken,
};
}
}