From 49567cbb43e77fee0731d30870eccd33a38225a8 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Thu, 22 Jan 2026 22:54:47 +0300 Subject: [PATCH 01/13] feat: [Insights] [Release 1] Top Categories - Add a limit filter to search --- src/CONST/index.ts | 2 + src/components/Search/types.ts | 1 + src/libs/SearchAutocompleteUtils.ts | 5 + src/libs/SearchParser/autocompleteParser.js | 684 +++++++++--------- .../SearchParser/autocompleteParser.peggy | 3 +- src/libs/SearchParser/baseRules.peggy | 1 + src/libs/SearchParser/searchParser.js | 684 +++++++++--------- src/libs/SearchParser/searchParser.peggy | 4 +- src/libs/SearchQueryUtils.ts | 23 +- tests/unit/Search/SearchQueryUtilsTest.ts | 77 ++ tests/unit/SearchAutocompleteParserTest.ts | 47 ++ tests/unit/SearchAutocompleteUtilsTest.ts | 54 ++ tests/unit/SearchParserTest.ts | 66 ++ 13 files changed, 988 insertions(+), 663 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 2b6e2f223baec..7012a79e9e4b8 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -7047,6 +7047,7 @@ const CONST = { SORT_ORDER: 'sortOrder', GROUP_BY: 'groupBy', COLUMNS: 'columns', + LIMIT: 'limit', }, SYNTAX_FILTER_KEYS: { TYPE: 'type', @@ -7156,6 +7157,7 @@ const CONST = { IS: 'is', REPORT_FIELD: 'report-field', COLUMNS: 'columns', + LIMIT: 'limit', }, get SEARCH_USER_FRIENDLY_VALUES_MAP() { return { diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index b4272937bfeda..204386a343a31 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -243,6 +243,7 @@ type SearchQueryAST = { policyID?: string[]; rawFilterList?: RawQueryFilter[]; columns?: SearchCustomColumnIds | SearchCustomColumnIds[]; + limit?: number; }; type SearchQueryJSON = { diff --git a/src/libs/SearchAutocompleteUtils.ts b/src/libs/SearchAutocompleteUtils.ts index 11a0b8db52dad..96f593e79aefb 100644 --- a/src/libs/SearchAutocompleteUtils.ts +++ b/src/libs/SearchAutocompleteUtils.ts @@ -170,6 +170,11 @@ function filterOutRangesWithCorrectValue( return range.value.length > 0; } + if ((range.key as string) === CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT) { + const num = Number(range.value); + return Number.isInteger(num) && num > 0; + } + switch (range.key) { case CONST.SEARCH.SYNTAX_FILTER_KEYS.IN: case CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE: diff --git a/src/libs/SearchParser/autocompleteParser.js b/src/libs/SearchParser/autocompleteParser.js index 73a7088207594..0862c2b776175 100644 --- a/src/libs/SearchParser/autocompleteParser.js +++ b/src/libs/SearchParser/autocompleteParser.js @@ -233,48 +233,49 @@ function peg$parse(input, options) { var peg$c47 = "withdrawn"; var peg$c48 = "groupby"; var peg$c49 = "group-by"; - var peg$c50 = "feed"; - var peg$c51 = "title"; - var peg$c52 = "assignee"; - var peg$c53 = "createdby"; - var peg$c54 = "created-by"; - var peg$c55 = "action"; - var peg$c56 = "total"; - var peg$c57 = "has"; - var peg$c58 = "is"; - var peg$c59 = "purchaseamount"; - var peg$c60 = "purchase-amount"; - var peg$c61 = "purchasecurrency"; - var peg$c62 = "purchase-currency"; - var peg$c63 = "columns"; - var peg$c64 = "per-diem"; - var peg$c65 = "drafts"; - var peg$c66 = "draft"; - var peg$c67 = "original-amount"; - var peg$c68 = "tax"; - var peg$c69 = "policy-name"; - var peg$c70 = "bank-account"; - var peg$c71 = "long-report-id"; - var peg$c72 = "exported-to"; - var peg$c73 = "exchange-rate"; - var peg$c74 = "reimbursable-total"; - var peg$c75 = "non-reimbursable-total"; - var peg$c76 = "group-from"; - var peg$c77 = "group-expenses"; - var peg$c78 = "group-total"; - var peg$c79 = "group-card"; - var peg$c80 = "group-feed"; - var peg$c81 = "group-bank-account"; - var peg$c82 = "group-withdrawn"; - var peg$c83 = "group-withdrawal-id"; - var peg$c84 = "!="; - var peg$c85 = ">="; - var peg$c86 = ">"; - var peg$c87 = "<="; - var peg$c88 = "<"; - var peg$c89 = "\u201C"; - var peg$c90 = "\u201D"; - var peg$c91 = "\""; + var peg$c50 = "limit"; + var peg$c51 = "feed"; + var peg$c52 = "title"; + var peg$c53 = "assignee"; + var peg$c54 = "createdby"; + var peg$c55 = "created-by"; + var peg$c56 = "action"; + var peg$c57 = "total"; + var peg$c58 = "has"; + var peg$c59 = "is"; + var peg$c60 = "purchaseamount"; + var peg$c61 = "purchase-amount"; + var peg$c62 = "purchasecurrency"; + var peg$c63 = "purchase-currency"; + var peg$c64 = "columns"; + var peg$c65 = "per-diem"; + var peg$c66 = "drafts"; + var peg$c67 = "draft"; + var peg$c68 = "original-amount"; + var peg$c69 = "tax"; + var peg$c70 = "policy-name"; + var peg$c71 = "bank-account"; + var peg$c72 = "long-report-id"; + var peg$c73 = "exported-to"; + var peg$c74 = "exchange-rate"; + var peg$c75 = "reimbursable-total"; + var peg$c76 = "non-reimbursable-total"; + var peg$c77 = "group-from"; + var peg$c78 = "group-expenses"; + var peg$c79 = "group-total"; + var peg$c80 = "group-card"; + var peg$c81 = "group-feed"; + var peg$c82 = "group-bank-account"; + var peg$c83 = "group-withdrawn"; + var peg$c84 = "group-withdrawal-id"; + var peg$c85 = "!="; + var peg$c86 = ">="; + var peg$c87 = ">"; + var peg$c88 = "<="; + var peg$c89 = "<"; + var peg$c90 = "\u201C"; + var peg$c91 = "\u201D"; + var peg$c92 = "\""; var peg$r0 = /^[ \t\r\n\xA0,:=<>!]/; var peg$r1 = /^[:=]/; @@ -343,64 +344,65 @@ function peg$parse(input, options) { var peg$e50 = peg$literalExpectation("withdrawn", true); var peg$e51 = peg$literalExpectation("groupBy", true); var peg$e52 = peg$literalExpectation("group-by", true); - var peg$e53 = peg$literalExpectation("feed", true); - var peg$e54 = peg$literalExpectation("title", true); - var peg$e55 = peg$literalExpectation("assignee", true); - var peg$e56 = peg$literalExpectation("createdBy", true); - var peg$e57 = peg$literalExpectation("created-by", true); - var peg$e58 = peg$literalExpectation("action", true); - var peg$e59 = peg$literalExpectation("total", true); - var peg$e60 = peg$literalExpectation("has", true); - var peg$e61 = peg$literalExpectation("is", true); - var peg$e62 = peg$literalExpectation("purchaseAmount", true); - var peg$e63 = peg$literalExpectation("purchase-amount", true); - var peg$e64 = peg$literalExpectation("purchaseCurrency", true); - var peg$e65 = peg$literalExpectation("purchase-currency", true); - var peg$e66 = peg$literalExpectation("columns", true); - var peg$e67 = peg$literalExpectation("per-diem", true); - var peg$e68 = peg$literalExpectation("drafts", true); - var peg$e69 = peg$literalExpectation("draft", true); - var peg$e70 = peg$literalExpectation("original-amount", true); - var peg$e71 = peg$literalExpectation("tax", true); - var peg$e72 = peg$literalExpectation("policy-name", true); - var peg$e73 = peg$literalExpectation("bank-account", true); - var peg$e74 = peg$literalExpectation("long-report-id", true); - var peg$e75 = peg$literalExpectation("exported-to", true); - var peg$e76 = peg$literalExpectation("exchange-rate", true); - var peg$e77 = peg$literalExpectation("reimbursable-total", true); - var peg$e78 = peg$literalExpectation("non-reimbursable-total", true); - var peg$e79 = peg$literalExpectation("group-from", true); - var peg$e80 = peg$literalExpectation("group-expenses", true); - var peg$e81 = peg$literalExpectation("group-total", true); - var peg$e82 = peg$literalExpectation("group-card", true); - var peg$e83 = peg$literalExpectation("group-feed", true); - var peg$e84 = peg$literalExpectation("group-bank-account", true); - var peg$e85 = peg$literalExpectation("group-withdrawn", true); - var peg$e86 = peg$literalExpectation("group-withdrawal-id", true); - var peg$e87 = peg$otherExpectation("operator"); - var peg$e88 = peg$classExpectation([":", "="], false, false); - var peg$e89 = peg$literalExpectation("!=", false); - var peg$e90 = peg$literalExpectation(">=", false); - var peg$e91 = peg$literalExpectation(">", false); - var peg$e92 = peg$literalExpectation("<=", false); - var peg$e93 = peg$literalExpectation("<", false); - var peg$e94 = peg$otherExpectation("word"); - var peg$e95 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e96 = peg$otherExpectation("whitespace"); - var peg$e97 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); - var peg$e98 = peg$otherExpectation("quote"); - var peg$e99 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e100 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); - var peg$e101 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); - var peg$e102 = peg$literalExpectation("\u201C", false); - var peg$e103 = peg$literalExpectation("\u201D", false); - var peg$e104 = peg$literalExpectation("\"", false); - var peg$e105 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e106 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e107 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); - var peg$e108 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); - var peg$e109 = peg$classExpectation([","], false, false); - var peg$e110 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ","], false, false); + var peg$e53 = peg$literalExpectation("limit", true); + var peg$e54 = peg$literalExpectation("feed", true); + var peg$e55 = peg$literalExpectation("title", true); + var peg$e56 = peg$literalExpectation("assignee", true); + var peg$e57 = peg$literalExpectation("createdBy", true); + var peg$e58 = peg$literalExpectation("created-by", true); + var peg$e59 = peg$literalExpectation("action", true); + var peg$e60 = peg$literalExpectation("total", true); + var peg$e61 = peg$literalExpectation("has", true); + var peg$e62 = peg$literalExpectation("is", true); + var peg$e63 = peg$literalExpectation("purchaseAmount", true); + var peg$e64 = peg$literalExpectation("purchase-amount", true); + var peg$e65 = peg$literalExpectation("purchaseCurrency", true); + var peg$e66 = peg$literalExpectation("purchase-currency", true); + var peg$e67 = peg$literalExpectation("columns", true); + var peg$e68 = peg$literalExpectation("per-diem", true); + var peg$e69 = peg$literalExpectation("drafts", true); + var peg$e70 = peg$literalExpectation("draft", true); + var peg$e71 = peg$literalExpectation("original-amount", true); + var peg$e72 = peg$literalExpectation("tax", true); + var peg$e73 = peg$literalExpectation("policy-name", true); + var peg$e74 = peg$literalExpectation("bank-account", true); + var peg$e75 = peg$literalExpectation("long-report-id", true); + var peg$e76 = peg$literalExpectation("exported-to", true); + var peg$e77 = peg$literalExpectation("exchange-rate", true); + var peg$e78 = peg$literalExpectation("reimbursable-total", true); + var peg$e79 = peg$literalExpectation("non-reimbursable-total", true); + var peg$e80 = peg$literalExpectation("group-from", true); + var peg$e81 = peg$literalExpectation("group-expenses", true); + var peg$e82 = peg$literalExpectation("group-total", true); + var peg$e83 = peg$literalExpectation("group-card", true); + var peg$e84 = peg$literalExpectation("group-feed", true); + var peg$e85 = peg$literalExpectation("group-bank-account", true); + var peg$e86 = peg$literalExpectation("group-withdrawn", true); + var peg$e87 = peg$literalExpectation("group-withdrawal-id", true); + var peg$e88 = peg$otherExpectation("operator"); + var peg$e89 = peg$classExpectation([":", "="], false, false); + var peg$e90 = peg$literalExpectation("!=", false); + var peg$e91 = peg$literalExpectation(">=", false); + var peg$e92 = peg$literalExpectation(">", false); + var peg$e93 = peg$literalExpectation("<=", false); + var peg$e94 = peg$literalExpectation("<", false); + var peg$e95 = peg$otherExpectation("word"); + var peg$e96 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e97 = peg$otherExpectation("whitespace"); + var peg$e98 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); + var peg$e99 = peg$otherExpectation("quote"); + var peg$e100 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e101 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); + var peg$e102 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); + var peg$e103 = peg$literalExpectation("\u201C", false); + var peg$e104 = peg$literalExpectation("\u201D", false); + var peg$e105 = peg$literalExpectation("\"", false); + var peg$e106 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e107 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e108 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); + var peg$e109 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); + var peg$e110 = peg$classExpectation([","], false, false); + var peg$e111 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ","], false, false); var peg$f0 = function(ranges) { return { autocomplete, ranges }; }; var peg$f1 = function(filters) { return filters.filter(Boolean).flat(); }; @@ -499,69 +501,70 @@ function peg$parse(input, options) { var peg$f39 = function() { return "posted"; }; var peg$f40 = function() { return "withdrawn"; }; var peg$f41 = function() { return "groupBy"; }; - var peg$f42 = function() { return "feed"; }; - var peg$f43 = function() { return "title"; }; - var peg$f44 = function() { return "assignee"; }; - var peg$f45 = function() { return "createdBy"; }; - var peg$f46 = function() { return "action"; }; - var peg$f47 = function() {return "total"; }; - var peg$f48 = function() {return "has"; }; - var peg$f49 = function() {return "is"; }; - var peg$f50 = function() {return "purchaseAmount"}; - var peg$f51 = function() {return "purchaseCurrency"}; - var peg$f52 = function() { + var peg$f42 = function() { return "limit"; }; + var peg$f43 = function() { return "feed"; }; + var peg$f44 = function() { return "title"; }; + var peg$f45 = function() { return "assignee"; }; + var peg$f46 = function() { return "createdBy"; }; + var peg$f47 = function() { return "action"; }; + var peg$f48 = function() {return "total"; }; + var peg$f49 = function() {return "has"; }; + var peg$f50 = function() {return "is"; }; + var peg$f51 = function() {return "purchaseAmount"}; + var peg$f52 = function() {return "purchaseCurrency"}; + var peg$f53 = function() { isColumnsContext = true; return "columns"; }; - var peg$f53 = function() { return isColumnsContext; }; - var peg$f54 = function() { return "perDiem"; }; - var peg$f55 = function() { return "drafts"; }; - var peg$f56 = function() { return "originalamount"; }; - var peg$f57 = function() { return "taxAmount"; }; - var peg$f58 = function() { return "taxrate"; }; - var peg$f59 = function() { return "policyname"; }; - var peg$f60 = function() { return "withdrawalID"; }; - var peg$f61 = function() { return "bankAccount"; }; - var peg$f62 = function() { return "reportID"; }; - var peg$f63 = function() { return "base62ReportID"; }; - var peg$f64 = function() { return "exportedto"; }; - var peg$f65 = function() { return "exchangeRate"; }; - var peg$f66 = function() { return "reimbursableTotal"; }; - var peg$f67 = function() { return "nonReimbursableTotal"; }; - var peg$f68 = function() { return "groupFrom"; }; - var peg$f69 = function() { return "groupExpenses"; }; - var peg$f70 = function() { return "groupTotal"; }; - var peg$f71 = function() { return "groupCard"; }; - var peg$f72 = function() { return "groupFeed"; }; - var peg$f73 = function() { return "groupBankAccount"; }; - var peg$f74 = function() { return "groupWithdrawn"; }; - var peg$f75 = function() { return "groupWithdrawalID"; }; - var peg$f76 = function() { return "eq"; }; - var peg$f77 = function() { return "neq"; }; - var peg$f78 = function() { return "gte"; }; - var peg$f79 = function() { return "gt"; }; - var peg$f80 = function() { return "lte"; }; - var peg$f81 = function() { return "lt"; }; - var peg$f82 = function(o) { + var peg$f54 = function() { return isColumnsContext; }; + var peg$f55 = function() { return "perDiem"; }; + var peg$f56 = function() { return "drafts"; }; + var peg$f57 = function() { return "originalamount"; }; + var peg$f58 = function() { return "taxAmount"; }; + var peg$f59 = function() { return "taxrate"; }; + var peg$f60 = function() { return "policyname"; }; + var peg$f61 = function() { return "withdrawalID"; }; + var peg$f62 = function() { return "bankAccount"; }; + var peg$f63 = function() { return "reportID"; }; + var peg$f64 = function() { return "base62ReportID"; }; + var peg$f65 = function() { return "exportedto"; }; + var peg$f66 = function() { return "exchangeRate"; }; + var peg$f67 = function() { return "reimbursableTotal"; }; + var peg$f68 = function() { return "nonReimbursableTotal"; }; + var peg$f69 = function() { return "groupFrom"; }; + var peg$f70 = function() { return "groupExpenses"; }; + var peg$f71 = function() { return "groupTotal"; }; + var peg$f72 = function() { return "groupCard"; }; + var peg$f73 = function() { return "groupFeed"; }; + var peg$f74 = function() { return "groupBankAccount"; }; + var peg$f75 = function() { return "groupWithdrawn"; }; + var peg$f76 = function() { return "groupWithdrawalID"; }; + var peg$f77 = function() { return "eq"; }; + var peg$f78 = function() { return "neq"; }; + var peg$f79 = function() { return "gte"; }; + var peg$f80 = function() { return "gt"; }; + var peg$f81 = function() { return "lte"; }; + var peg$f82 = function() { return "lt"; }; + var peg$f83 = function(o) { if (nameOperator) { expectingNestedQuote = (o === "eq"); // Use simple parser if no valid operator is found } isColumnsContext = false; return o; }; - var peg$f83 = function(chars) { return chars.join("").trim(); }; - var peg$f84 = function() { + var peg$f84 = function(chars) { return chars.join("").trim(); }; + var peg$f85 = function() { isColumnsContext = false; return "and"; }; - var peg$f85 = function() { return expectingNestedQuote; }; - var peg$f86 = function(start, inner, end) { //handle no-breaking space + var peg$f86 = function() { return expectingNestedQuote; }; + var peg$f87 = function(start, inner, end) { //handle no-breaking space return [...start, '"', ...inner, '"', ...end].join(""); }; - var peg$f87 = function(start) {return "“"}; - var peg$f88 = function(start) {return "”"}; - var peg$f89 = function(start) {return "\""}; - var peg$f90 = function(start, inner, end) { + var peg$f88 = function(start) {return "“"}; + var peg$f89 = function(start) {return "”"}; + var peg$f90 = function(start) {return "\""}; + var peg$f91 = function(start, inner, end) { return [...start, '"', ...inner, '"'].join(""); }; var peg$currPos = options.peg$currPos | 0; @@ -1061,6 +1064,9 @@ function peg$parse(input, options) { s1 = peg$parsereportFieldDynamic(); if (s1 === peg$FAILED) { s1 = peg$parsecolumns(); + if (s1 === peg$FAILED) { + s1 = peg$parselimit(); + } } } } @@ -1994,13 +2000,13 @@ function peg$parse(input, options) { return s0; } - function peg$parsefeed() { + function peg$parselimit() { var s0, s1; s0 = peg$currPos; - s1 = input.substr(peg$currPos, 4); + s1 = input.substr(peg$currPos, 5); if (s1.toLowerCase() === peg$c50) { - peg$currPos += 4; + peg$currPos += 5; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e53); } @@ -2014,13 +2020,13 @@ function peg$parse(input, options) { return s0; } - function peg$parsetitle() { + function peg$parsefeed() { var s0, s1; s0 = peg$currPos; - s1 = input.substr(peg$currPos, 5); + s1 = input.substr(peg$currPos, 4); if (s1.toLowerCase() === peg$c51) { - peg$currPos += 5; + peg$currPos += 4; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e54); } @@ -2034,13 +2040,13 @@ function peg$parse(input, options) { return s0; } - function peg$parseassignee() { + function peg$parsetitle() { var s0, s1; s0 = peg$currPos; - s1 = input.substr(peg$currPos, 8); + s1 = input.substr(peg$currPos, 5); if (s1.toLowerCase() === peg$c52) { - peg$currPos += 8; + peg$currPos += 5; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e55); } @@ -2054,28 +2060,48 @@ function peg$parse(input, options) { return s0; } + function peg$parseassignee() { + var s0, s1; + + s0 = peg$currPos; + s1 = input.substr(peg$currPos, 8); + if (s1.toLowerCase() === peg$c53) { + peg$currPos += 8; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e56); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f45(); + } + s0 = s1; + + return s0; + } + function peg$parsecreatedBy() { var s0, s1; s0 = input.substr(peg$currPos, 9); - if (s0.toLowerCase() === peg$c53) { + if (s0.toLowerCase() === peg$c54) { peg$currPos += 9; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e56); } + if (peg$silentFails === 0) { peg$fail(peg$e57); } } if (s0 === peg$FAILED) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 10); - if (s1.toLowerCase() === peg$c54) { + if (s1.toLowerCase() === peg$c55) { peg$currPos += 10; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e57); } + if (peg$silentFails === 0) { peg$fail(peg$e58); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f45(); + s1 = peg$f46(); } s0 = s1; } @@ -2088,15 +2114,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 6); - if (s1.toLowerCase() === peg$c55) { + if (s1.toLowerCase() === peg$c56) { peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e58); } + if (peg$silentFails === 0) { peg$fail(peg$e59); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f46(); + s1 = peg$f47(); } s0 = s1; @@ -2108,15 +2134,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 5); - if (s1.toLowerCase() === peg$c56) { + if (s1.toLowerCase() === peg$c57) { peg$currPos += 5; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e59); } + if (peg$silentFails === 0) { peg$fail(peg$e60); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f47(); + s1 = peg$f48(); } s0 = s1; @@ -2128,15 +2154,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 3); - if (s1.toLowerCase() === peg$c57) { + if (s1.toLowerCase() === peg$c58) { peg$currPos += 3; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e60); } + if (peg$silentFails === 0) { peg$fail(peg$e61); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f48(); + s1 = peg$f49(); } s0 = s1; @@ -2148,15 +2174,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 2); - if (s1.toLowerCase() === peg$c58) { + if (s1.toLowerCase() === peg$c59) { peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e61); } + if (peg$silentFails === 0) { peg$fail(peg$e62); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f49(); + s1 = peg$f50(); } s0 = s1; @@ -2167,24 +2193,24 @@ function peg$parse(input, options) { var s0, s1; s0 = input.substr(peg$currPos, 14); - if (s0.toLowerCase() === peg$c59) { + if (s0.toLowerCase() === peg$c60) { peg$currPos += 14; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e63); } } if (s0 === peg$FAILED) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 15); - if (s1.toLowerCase() === peg$c60) { + if (s1.toLowerCase() === peg$c61) { peg$currPos += 15; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e63); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f50(); + s1 = peg$f51(); } s0 = s1; } @@ -2196,24 +2222,24 @@ function peg$parse(input, options) { var s0, s1; s0 = input.substr(peg$currPos, 16); - if (s0.toLowerCase() === peg$c61) { + if (s0.toLowerCase() === peg$c62) { peg$currPos += 16; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e64); } + if (peg$silentFails === 0) { peg$fail(peg$e65); } } if (s0 === peg$FAILED) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 17); - if (s1.toLowerCase() === peg$c62) { + if (s1.toLowerCase() === peg$c63) { peg$currPos += 17; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e65); } + if (peg$silentFails === 0) { peg$fail(peg$e66); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f51(); + s1 = peg$f52(); } s0 = s1; } @@ -2226,15 +2252,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 7); - if (s1.toLowerCase() === peg$c63) { + if (s1.toLowerCase() === peg$c64) { peg$currPos += 7; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e66); } + if (peg$silentFails === 0) { peg$fail(peg$e67); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f52(); + s1 = peg$f53(); } s0 = s1; @@ -2246,7 +2272,7 @@ function peg$parse(input, options) { s0 = peg$currPos; peg$savedPos = peg$currPos; - s1 = peg$f53(); + s1 = peg$f54(); if (s1) { s1 = undefined; } else { @@ -2345,11 +2371,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 8); - if (s1.toLowerCase() === peg$c64) { + if (s1.toLowerCase() === peg$c65) { peg$currPos += 8; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e67); } + if (peg$silentFails === 0) { peg$fail(peg$e68); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2364,7 +2390,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f54(); + s0 = peg$f55(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2382,19 +2408,19 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 6); - if (s1.toLowerCase() === peg$c65) { + if (s1.toLowerCase() === peg$c66) { peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e68); } + if (peg$silentFails === 0) { peg$fail(peg$e69); } } if (s1 === peg$FAILED) { s1 = input.substr(peg$currPos, 5); - if (s1.toLowerCase() === peg$c66) { + if (s1.toLowerCase() === peg$c67) { peg$currPos += 5; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e69); } + if (peg$silentFails === 0) { peg$fail(peg$e70); } } } if (s1 !== peg$FAILED) { @@ -2410,7 +2436,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f55(); + s0 = peg$f56(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2428,11 +2454,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 15); - if (s1.toLowerCase() === peg$c67) { + if (s1.toLowerCase() === peg$c68) { peg$currPos += 15; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e70); } + if (peg$silentFails === 0) { peg$fail(peg$e71); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2447,7 +2473,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f56(); + s0 = peg$f57(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2465,11 +2491,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 3); - if (s1.toLowerCase() === peg$c68) { + if (s1.toLowerCase() === peg$c69) { peg$currPos += 3; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e71); } + if (peg$silentFails === 0) { peg$fail(peg$e72); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2484,7 +2510,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f57(); + s0 = peg$f58(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2521,7 +2547,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f58(); + s0 = peg$f59(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2539,11 +2565,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 11); - if (s1.toLowerCase() === peg$c69) { + if (s1.toLowerCase() === peg$c70) { peg$currPos += 11; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e72); } + if (peg$silentFails === 0) { peg$fail(peg$e73); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2558,7 +2584,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f59(); + s0 = peg$f60(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2595,7 +2621,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f60(); + s0 = peg$f61(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2613,11 +2639,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 12); - if (s1.toLowerCase() === peg$c70) { + if (s1.toLowerCase() === peg$c71) { peg$currPos += 12; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e73); } + if (peg$silentFails === 0) { peg$fail(peg$e74); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2632,7 +2658,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f61(); + s0 = peg$f62(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2650,11 +2676,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 14); - if (s1.toLowerCase() === peg$c71) { + if (s1.toLowerCase() === peg$c72) { peg$currPos += 14; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e74); } + if (peg$silentFails === 0) { peg$fail(peg$e75); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2669,7 +2695,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f62(); + s0 = peg$f63(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2706,7 +2732,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f63(); + s0 = peg$f64(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2724,11 +2750,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 11); - if (s1.toLowerCase() === peg$c72) { + if (s1.toLowerCase() === peg$c73) { peg$currPos += 11; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e75); } + if (peg$silentFails === 0) { peg$fail(peg$e76); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2743,7 +2769,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f64(); + s0 = peg$f65(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2761,11 +2787,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 13); - if (s1.toLowerCase() === peg$c73) { + if (s1.toLowerCase() === peg$c74) { peg$currPos += 13; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e76); } + if (peg$silentFails === 0) { peg$fail(peg$e77); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2780,7 +2806,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f65(); + s0 = peg$f66(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2798,11 +2824,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 18); - if (s1.toLowerCase() === peg$c74) { + if (s1.toLowerCase() === peg$c75) { peg$currPos += 18; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e77); } + if (peg$silentFails === 0) { peg$fail(peg$e78); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2817,7 +2843,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f66(); + s0 = peg$f67(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2835,11 +2861,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 22); - if (s1.toLowerCase() === peg$c75) { + if (s1.toLowerCase() === peg$c76) { peg$currPos += 22; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e78); } + if (peg$silentFails === 0) { peg$fail(peg$e79); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2854,7 +2880,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f67(); + s0 = peg$f68(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2872,11 +2898,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 10); - if (s1.toLowerCase() === peg$c76) { + if (s1.toLowerCase() === peg$c77) { peg$currPos += 10; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e79); } + if (peg$silentFails === 0) { peg$fail(peg$e80); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2891,7 +2917,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f68(); + s0 = peg$f69(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2909,11 +2935,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 14); - if (s1.toLowerCase() === peg$c77) { + if (s1.toLowerCase() === peg$c78) { peg$currPos += 14; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e81); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2928,7 +2954,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f69(); + s0 = peg$f70(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2946,11 +2972,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 11); - if (s1.toLowerCase() === peg$c78) { + if (s1.toLowerCase() === peg$c79) { peg$currPos += 11; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e81); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2965,7 +2991,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f70(); + s0 = peg$f71(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2983,11 +3009,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 10); - if (s1.toLowerCase() === peg$c79) { + if (s1.toLowerCase() === peg$c80) { peg$currPos += 10; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e82); } + if (peg$silentFails === 0) { peg$fail(peg$e83); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3002,7 +3028,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f71(); + s0 = peg$f72(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3020,11 +3046,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 10); - if (s1.toLowerCase() === peg$c80) { + if (s1.toLowerCase() === peg$c81) { peg$currPos += 10; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e83); } + if (peg$silentFails === 0) { peg$fail(peg$e84); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3039,7 +3065,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f72(); + s0 = peg$f73(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3057,11 +3083,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 18); - if (s1.toLowerCase() === peg$c81) { + if (s1.toLowerCase() === peg$c82) { peg$currPos += 18; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e84); } + if (peg$silentFails === 0) { peg$fail(peg$e85); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3076,7 +3102,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f73(); + s0 = peg$f74(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3094,11 +3120,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 15); - if (s1.toLowerCase() === peg$c82) { + if (s1.toLowerCase() === peg$c83) { peg$currPos += 15; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e85); } + if (peg$silentFails === 0) { peg$fail(peg$e86); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3113,7 +3139,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f74(); + s0 = peg$f75(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3131,11 +3157,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 19); - if (s1.toLowerCase() === peg$c83) { + if (s1.toLowerCase() === peg$c84) { peg$currPos += 19; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e86); } + if (peg$silentFails === 0) { peg$fail(peg$e87); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3150,7 +3176,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f75(); + s0 = peg$f76(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3173,81 +3199,81 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e88); } + if (peg$silentFails === 0) { peg$fail(peg$e89); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f76(); + s1 = peg$f77(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c84) { - s1 = peg$c84; + if (input.substr(peg$currPos, 2) === peg$c85) { + s1 = peg$c85; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e89); } + if (peg$silentFails === 0) { peg$fail(peg$e90); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f77(); + s1 = peg$f78(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c85) { - s1 = peg$c85; + if (input.substr(peg$currPos, 2) === peg$c86) { + s1 = peg$c86; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e90); } + if (peg$silentFails === 0) { peg$fail(peg$e91); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f78(); + s1 = peg$f79(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c86; + s1 = peg$c87; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e91); } + if (peg$silentFails === 0) { peg$fail(peg$e92); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f79(); + s1 = peg$f80(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c87) { - s1 = peg$c87; + if (input.substr(peg$currPos, 2) === peg$c88) { + s1 = peg$c88; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e92); } + if (peg$silentFails === 0) { peg$fail(peg$e93); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f80(); + s1 = peg$f81(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c88; + s1 = peg$c89; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e93); } + if (peg$silentFails === 0) { peg$fail(peg$e94); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f81(); + s1 = peg$f82(); } s0 = s1; } @@ -3258,7 +3284,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e87); } + if (peg$silentFails === 0) { peg$fail(peg$e88); } } return s0; @@ -3271,7 +3297,7 @@ function peg$parse(input, options) { s1 = peg$parseoperator(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f82(s1); + s1 = peg$f83(s1); } s0 = s1; @@ -3289,7 +3315,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e95); } + if (peg$silentFails === 0) { peg$fail(peg$e96); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { @@ -3299,7 +3325,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e95); } + if (peg$silentFails === 0) { peg$fail(peg$e96); } } } } else { @@ -3307,13 +3333,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f83(s1); + s1 = peg$f84(s1); } s0 = s1; peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e94); } + if (peg$silentFails === 0) { peg$fail(peg$e95); } } return s0; @@ -3325,7 +3351,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$parse_(); peg$savedPos = s0; - s1 = peg$f84(); + s1 = peg$f85(); s0 = s1; return s0; @@ -3341,7 +3367,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e97); } + if (peg$silentFails === 0) { peg$fail(peg$e98); } } while (s1 !== peg$FAILED) { s0.push(s1); @@ -3350,12 +3376,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e97); } + if (peg$silentFails === 0) { peg$fail(peg$e98); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e96); } + if (peg$silentFails === 0) { peg$fail(peg$e97); } return s0; } @@ -3365,7 +3391,7 @@ function peg$parse(input, options) { s0 = peg$currPos; peg$savedPos = peg$currPos; - s1 = peg$f85(); + s1 = peg$f86(); if (s1) { s1 = undefined; } else { @@ -3402,7 +3428,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e99); } + if (peg$silentFails === 0) { peg$fail(peg$e100); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -3411,7 +3437,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e99); } + if (peg$silentFails === 0) { peg$fail(peg$e100); } } } s2 = input.charAt(peg$currPos); @@ -3419,7 +3445,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e100); } + if (peg$silentFails === 0) { peg$fail(peg$e101); } } if (s2 !== peg$FAILED) { s3 = []; @@ -3428,7 +3454,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e101); } + if (peg$silentFails === 0) { peg$fail(peg$e102); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -3437,7 +3463,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e101); } + if (peg$silentFails === 0) { peg$fail(peg$e102); } } } s4 = input.charAt(peg$currPos); @@ -3445,7 +3471,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e100); } + if (peg$silentFails === 0) { peg$fail(peg$e101); } } if (s4 !== peg$FAILED) { s5 = []; @@ -3454,7 +3480,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e95); } + if (peg$silentFails === 0) { peg$fail(peg$e96); } } while (s6 !== peg$FAILED) { s5.push(s6); @@ -3463,11 +3489,11 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e95); } + if (peg$silentFails === 0) { peg$fail(peg$e96); } } } peg$savedPos = s0; - s0 = peg$f86(s1, s3, s5); + s0 = peg$f87(s1, s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3479,7 +3505,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e98); } + if (peg$silentFails === 0) { peg$fail(peg$e99); } } return s0; @@ -3496,7 +3522,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e99); } + if (peg$silentFails === 0) { peg$fail(peg$e100); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -3505,7 +3531,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e99); } + if (peg$silentFails === 0) { peg$fail(peg$e100); } } } s2 = input.charAt(peg$currPos); @@ -3513,7 +3539,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e100); } + if (peg$silentFails === 0) { peg$fail(peg$e101); } } if (s2 !== peg$FAILED) { s3 = []; @@ -3522,7 +3548,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e101); } + if (peg$silentFails === 0) { peg$fail(peg$e102); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -3538,15 +3564,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c89; + s6 = peg$c90; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e102); } + if (peg$silentFails === 0) { peg$fail(peg$e103); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f87(s1); + s4 = peg$f88(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3569,15 +3595,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c90; + s6 = peg$c91; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e103); } + if (peg$silentFails === 0) { peg$fail(peg$e104); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f88(s1); + s4 = peg$f89(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3600,15 +3626,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c91; + s6 = peg$c92; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e104); } + if (peg$silentFails === 0) { peg$fail(peg$e105); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f89(s1); + s4 = peg$f90(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3627,7 +3653,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e101); } + if (peg$silentFails === 0) { peg$fail(peg$e102); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -3643,15 +3669,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c89; + s6 = peg$c90; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e102); } + if (peg$silentFails === 0) { peg$fail(peg$e103); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f87(s1); + s4 = peg$f88(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3674,15 +3700,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c90; + s6 = peg$c91; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e103); } + if (peg$silentFails === 0) { peg$fail(peg$e104); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f88(s1); + s4 = peg$f89(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3705,15 +3731,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c91; + s6 = peg$c92; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e104); } + if (peg$silentFails === 0) { peg$fail(peg$e105); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f89(s1); + s4 = peg$f90(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3729,7 +3755,7 @@ function peg$parse(input, options) { s4 = peg$parseclosingQuote(); if (s4 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f90(s1, s3, s4); + s0 = peg$f91(s1, s3, s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3741,7 +3767,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e98); } + if (peg$silentFails === 0) { peg$fail(peg$e99); } } return s0; @@ -3756,7 +3782,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e100); } + if (peg$silentFails === 0) { peg$fail(peg$e101); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3794,7 +3820,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e105); } + if (peg$silentFails === 0) { peg$fail(peg$e106); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -3803,7 +3829,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e105); } + if (peg$silentFails === 0) { peg$fail(peg$e106); } } } s2 = []; @@ -3812,7 +3838,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e106); } + if (peg$silentFails === 0) { peg$fail(peg$e107); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -3821,7 +3847,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e106); } + if (peg$silentFails === 0) { peg$fail(peg$e107); } } } s3 = []; @@ -3830,7 +3856,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e107); } + if (peg$silentFails === 0) { peg$fail(peg$e108); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -3839,7 +3865,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e107); } + if (peg$silentFails === 0) { peg$fail(peg$e108); } } } s4 = peg$parseoperator(); @@ -3858,7 +3884,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e108); } + if (peg$silentFails === 0) { peg$fail(peg$e109); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -3867,7 +3893,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e108); } + if (peg$silentFails === 0) { peg$fail(peg$e109); } } } s2 = peg$currPos; @@ -3914,7 +3940,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e109); } + if (peg$silentFails === 0) { peg$fail(peg$e110); } } } } @@ -3930,7 +3956,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e110); } + if (peg$silentFails === 0) { peg$fail(peg$e111); } } if (s0 === peg$FAILED) { s0 = peg$currPos; @@ -3959,7 +3985,7 @@ function peg$parse(input, options) { // List fields where you cannot prefix it with "-" to negate it const nonNegatableKeys = new Set([ - "type", "keyword", "groupCurrency", "groupBy", "columns" + "type", "keyword", "groupCurrency", "groupBy", "columns", "limit" ]); diff --git a/src/libs/SearchParser/autocompleteParser.peggy b/src/libs/SearchParser/autocompleteParser.peggy index cda2b7c8c8882..4a6aee643960d 100644 --- a/src/libs/SearchParser/autocompleteParser.peggy +++ b/src/libs/SearchParser/autocompleteParser.peggy @@ -23,7 +23,7 @@ // List fields where you cannot prefix it with "-" to negate it const nonNegatableKeys = new Set([ - "type", "keyword", "groupCurrency", "groupBy", "columns" + "type", "keyword", "groupCurrency", "groupBy", "columns", "limit" ]); } @@ -119,6 +119,7 @@ autocompleteKey "key" / title / reportFieldDynamic / columns + / limit ) filterKey diff --git a/src/libs/SearchParser/baseRules.peggy b/src/libs/SearchParser/baseRules.peggy index 117d06056cdc0..d420bddb3b577 100644 --- a/src/libs/SearchParser/baseRules.peggy +++ b/src/libs/SearchParser/baseRules.peggy @@ -69,6 +69,7 @@ exported = "exported"i { return "exported"; } posted = "posted"i { return "posted"; } withdrawn = "withdrawn"i { return "withdrawn"; } groupBy = "groupBy"i / "group-by"i { return "groupBy"; } +limit = "limit"i { return "limit"; } feed = "feed"i { return "feed"; } title = "title"i { return "title"; } assignee = "assignee"i { return "assignee"; } diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index 4c74ad6062d8a..361f4f644125e 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -234,48 +234,49 @@ function peg$parse(input, options) { var peg$c47 = "withdrawn"; var peg$c48 = "groupby"; var peg$c49 = "group-by"; - var peg$c50 = "feed"; - var peg$c51 = "title"; - var peg$c52 = "assignee"; - var peg$c53 = "createdby"; - var peg$c54 = "created-by"; - var peg$c55 = "action"; - var peg$c56 = "total"; - var peg$c57 = "has"; - var peg$c58 = "is"; - var peg$c59 = "purchaseamount"; - var peg$c60 = "purchase-amount"; - var peg$c61 = "purchasecurrency"; - var peg$c62 = "purchase-currency"; - var peg$c63 = "columns"; - var peg$c64 = "per-diem"; - var peg$c65 = "drafts"; - var peg$c66 = "draft"; - var peg$c67 = "original-amount"; - var peg$c68 = "tax"; - var peg$c69 = "policy-name"; - var peg$c70 = "bank-account"; - var peg$c71 = "long-report-id"; - var peg$c72 = "exported-to"; - var peg$c73 = "exchange-rate"; - var peg$c74 = "reimbursable-total"; - var peg$c75 = "non-reimbursable-total"; - var peg$c76 = "group-from"; - var peg$c77 = "group-expenses"; - var peg$c78 = "group-total"; - var peg$c79 = "group-card"; - var peg$c80 = "group-feed"; - var peg$c81 = "group-bank-account"; - var peg$c82 = "group-withdrawn"; - var peg$c83 = "group-withdrawal-id"; - var peg$c84 = "!="; - var peg$c85 = ">="; - var peg$c86 = ">"; - var peg$c87 = "<="; - var peg$c88 = "<"; - var peg$c89 = "\u201C"; - var peg$c90 = "\u201D"; - var peg$c91 = "\""; + var peg$c50 = "limit"; + var peg$c51 = "feed"; + var peg$c52 = "title"; + var peg$c53 = "assignee"; + var peg$c54 = "createdby"; + var peg$c55 = "created-by"; + var peg$c56 = "action"; + var peg$c57 = "total"; + var peg$c58 = "has"; + var peg$c59 = "is"; + var peg$c60 = "purchaseamount"; + var peg$c61 = "purchase-amount"; + var peg$c62 = "purchasecurrency"; + var peg$c63 = "purchase-currency"; + var peg$c64 = "columns"; + var peg$c65 = "per-diem"; + var peg$c66 = "drafts"; + var peg$c67 = "draft"; + var peg$c68 = "original-amount"; + var peg$c69 = "tax"; + var peg$c70 = "policy-name"; + var peg$c71 = "bank-account"; + var peg$c72 = "long-report-id"; + var peg$c73 = "exported-to"; + var peg$c74 = "exchange-rate"; + var peg$c75 = "reimbursable-total"; + var peg$c76 = "non-reimbursable-total"; + var peg$c77 = "group-from"; + var peg$c78 = "group-expenses"; + var peg$c79 = "group-total"; + var peg$c80 = "group-card"; + var peg$c81 = "group-feed"; + var peg$c82 = "group-bank-account"; + var peg$c83 = "group-withdrawn"; + var peg$c84 = "group-withdrawal-id"; + var peg$c85 = "!="; + var peg$c86 = ">="; + var peg$c87 = ">"; + var peg$c88 = "<="; + var peg$c89 = "<"; + var peg$c90 = "\u201C"; + var peg$c91 = "\u201D"; + var peg$c92 = "\""; var peg$r0 = /^[^ \t\r\n\xA0]/; var peg$r1 = /^[ \t\r\n\xA0,:=<>!]/; @@ -347,64 +348,65 @@ function peg$parse(input, options) { var peg$e52 = peg$literalExpectation("withdrawn", true); var peg$e53 = peg$literalExpectation("groupBy", true); var peg$e54 = peg$literalExpectation("group-by", true); - var peg$e55 = peg$literalExpectation("feed", true); - var peg$e56 = peg$literalExpectation("title", true); - var peg$e57 = peg$literalExpectation("assignee", true); - var peg$e58 = peg$literalExpectation("createdBy", true); - var peg$e59 = peg$literalExpectation("created-by", true); - var peg$e60 = peg$literalExpectation("action", true); - var peg$e61 = peg$literalExpectation("total", true); - var peg$e62 = peg$literalExpectation("has", true); - var peg$e63 = peg$literalExpectation("is", true); - var peg$e64 = peg$literalExpectation("purchaseAmount", true); - var peg$e65 = peg$literalExpectation("purchase-amount", true); - var peg$e66 = peg$literalExpectation("purchaseCurrency", true); - var peg$e67 = peg$literalExpectation("purchase-currency", true); - var peg$e68 = peg$literalExpectation("columns", true); - var peg$e69 = peg$literalExpectation("per-diem", true); - var peg$e70 = peg$literalExpectation("drafts", true); - var peg$e71 = peg$literalExpectation("draft", true); - var peg$e72 = peg$literalExpectation("original-amount", true); - var peg$e73 = peg$literalExpectation("tax", true); - var peg$e74 = peg$literalExpectation("policy-name", true); - var peg$e75 = peg$literalExpectation("bank-account", true); - var peg$e76 = peg$literalExpectation("long-report-id", true); - var peg$e77 = peg$literalExpectation("exported-to", true); - var peg$e78 = peg$literalExpectation("exchange-rate", true); - var peg$e79 = peg$literalExpectation("reimbursable-total", true); - var peg$e80 = peg$literalExpectation("non-reimbursable-total", true); - var peg$e81 = peg$literalExpectation("group-from", true); - var peg$e82 = peg$literalExpectation("group-expenses", true); - var peg$e83 = peg$literalExpectation("group-total", true); - var peg$e84 = peg$literalExpectation("group-card", true); - var peg$e85 = peg$literalExpectation("group-feed", true); - var peg$e86 = peg$literalExpectation("group-bank-account", true); - var peg$e87 = peg$literalExpectation("group-withdrawn", true); - var peg$e88 = peg$literalExpectation("group-withdrawal-id", true); - var peg$e89 = peg$otherExpectation("operator"); - var peg$e90 = peg$classExpectation([":", "="], false, false); - var peg$e91 = peg$literalExpectation("!=", false); - var peg$e92 = peg$literalExpectation(">=", false); - var peg$e93 = peg$literalExpectation(">", false); - var peg$e94 = peg$literalExpectation("<=", false); - var peg$e95 = peg$literalExpectation("<", false); - var peg$e96 = peg$otherExpectation("word"); - var peg$e97 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e98 = peg$otherExpectation("whitespace"); - var peg$e99 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); - var peg$e100 = peg$otherExpectation("quote"); - var peg$e101 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e102 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); - var peg$e103 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); - var peg$e104 = peg$literalExpectation("\u201C", false); - var peg$e105 = peg$literalExpectation("\u201D", false); - var peg$e106 = peg$literalExpectation("\"", false); - var peg$e107 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e108 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e109 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); - var peg$e110 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); - var peg$e111 = peg$classExpectation([","], false, false); - var peg$e112 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ","], false, false); + var peg$e55 = peg$literalExpectation("limit", true); + var peg$e56 = peg$literalExpectation("feed", true); + var peg$e57 = peg$literalExpectation("title", true); + var peg$e58 = peg$literalExpectation("assignee", true); + var peg$e59 = peg$literalExpectation("createdBy", true); + var peg$e60 = peg$literalExpectation("created-by", true); + var peg$e61 = peg$literalExpectation("action", true); + var peg$e62 = peg$literalExpectation("total", true); + var peg$e63 = peg$literalExpectation("has", true); + var peg$e64 = peg$literalExpectation("is", true); + var peg$e65 = peg$literalExpectation("purchaseAmount", true); + var peg$e66 = peg$literalExpectation("purchase-amount", true); + var peg$e67 = peg$literalExpectation("purchaseCurrency", true); + var peg$e68 = peg$literalExpectation("purchase-currency", true); + var peg$e69 = peg$literalExpectation("columns", true); + var peg$e70 = peg$literalExpectation("per-diem", true); + var peg$e71 = peg$literalExpectation("drafts", true); + var peg$e72 = peg$literalExpectation("draft", true); + var peg$e73 = peg$literalExpectation("original-amount", true); + var peg$e74 = peg$literalExpectation("tax", true); + var peg$e75 = peg$literalExpectation("policy-name", true); + var peg$e76 = peg$literalExpectation("bank-account", true); + var peg$e77 = peg$literalExpectation("long-report-id", true); + var peg$e78 = peg$literalExpectation("exported-to", true); + var peg$e79 = peg$literalExpectation("exchange-rate", true); + var peg$e80 = peg$literalExpectation("reimbursable-total", true); + var peg$e81 = peg$literalExpectation("non-reimbursable-total", true); + var peg$e82 = peg$literalExpectation("group-from", true); + var peg$e83 = peg$literalExpectation("group-expenses", true); + var peg$e84 = peg$literalExpectation("group-total", true); + var peg$e85 = peg$literalExpectation("group-card", true); + var peg$e86 = peg$literalExpectation("group-feed", true); + var peg$e87 = peg$literalExpectation("group-bank-account", true); + var peg$e88 = peg$literalExpectation("group-withdrawn", true); + var peg$e89 = peg$literalExpectation("group-withdrawal-id", true); + var peg$e90 = peg$otherExpectation("operator"); + var peg$e91 = peg$classExpectation([":", "="], false, false); + var peg$e92 = peg$literalExpectation("!=", false); + var peg$e93 = peg$literalExpectation(">=", false); + var peg$e94 = peg$literalExpectation(">", false); + var peg$e95 = peg$literalExpectation("<=", false); + var peg$e96 = peg$literalExpectation("<", false); + var peg$e97 = peg$otherExpectation("word"); + var peg$e98 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e99 = peg$otherExpectation("whitespace"); + var peg$e100 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); + var peg$e101 = peg$otherExpectation("quote"); + var peg$e102 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e103 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); + var peg$e104 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); + var peg$e105 = peg$literalExpectation("\u201C", false); + var peg$e106 = peg$literalExpectation("\u201D", false); + var peg$e107 = peg$literalExpectation("\"", false); + var peg$e108 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e109 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e110 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); + var peg$e111 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); + var peg$e112 = peg$classExpectation([","], false, false); + var peg$e113 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ","], false, false); var peg$f0 = function(filters) { return applyDefaults(filters); }; var peg$f1 = function(head, tail) { @@ -526,69 +528,70 @@ function peg$parse(input, options) { var peg$f40 = function() { return "posted"; }; var peg$f41 = function() { return "withdrawn"; }; var peg$f42 = function() { return "groupBy"; }; - var peg$f43 = function() { return "feed"; }; - var peg$f44 = function() { return "title"; }; - var peg$f45 = function() { return "assignee"; }; - var peg$f46 = function() { return "createdBy"; }; - var peg$f47 = function() { return "action"; }; - var peg$f48 = function() {return "total"; }; - var peg$f49 = function() {return "has"; }; - var peg$f50 = function() {return "is"; }; - var peg$f51 = function() {return "purchaseAmount"}; - var peg$f52 = function() {return "purchaseCurrency"}; - var peg$f53 = function() { + var peg$f43 = function() { return "limit"; }; + var peg$f44 = function() { return "feed"; }; + var peg$f45 = function() { return "title"; }; + var peg$f46 = function() { return "assignee"; }; + var peg$f47 = function() { return "createdBy"; }; + var peg$f48 = function() { return "action"; }; + var peg$f49 = function() {return "total"; }; + var peg$f50 = function() {return "has"; }; + var peg$f51 = function() {return "is"; }; + var peg$f52 = function() {return "purchaseAmount"}; + var peg$f53 = function() {return "purchaseCurrency"}; + var peg$f54 = function() { isColumnsContext = true; return "columns"; }; - var peg$f54 = function() { return isColumnsContext; }; - var peg$f55 = function() { return "perDiem"; }; - var peg$f56 = function() { return "drafts"; }; - var peg$f57 = function() { return "originalamount"; }; - var peg$f58 = function() { return "taxAmount"; }; - var peg$f59 = function() { return "taxrate"; }; - var peg$f60 = function() { return "policyname"; }; - var peg$f61 = function() { return "withdrawalID"; }; - var peg$f62 = function() { return "bankAccount"; }; - var peg$f63 = function() { return "reportID"; }; - var peg$f64 = function() { return "base62ReportID"; }; - var peg$f65 = function() { return "exportedto"; }; - var peg$f66 = function() { return "exchangeRate"; }; - var peg$f67 = function() { return "reimbursableTotal"; }; - var peg$f68 = function() { return "nonReimbursableTotal"; }; - var peg$f69 = function() { return "groupFrom"; }; - var peg$f70 = function() { return "groupExpenses"; }; - var peg$f71 = function() { return "groupTotal"; }; - var peg$f72 = function() { return "groupCard"; }; - var peg$f73 = function() { return "groupFeed"; }; - var peg$f74 = function() { return "groupBankAccount"; }; - var peg$f75 = function() { return "groupWithdrawn"; }; - var peg$f76 = function() { return "groupWithdrawalID"; }; - var peg$f77 = function() { return "eq"; }; - var peg$f78 = function() { return "neq"; }; - var peg$f79 = function() { return "gte"; }; - var peg$f80 = function() { return "gt"; }; - var peg$f81 = function() { return "lte"; }; - var peg$f82 = function() { return "lt"; }; - var peg$f83 = function(o) { + var peg$f55 = function() { return isColumnsContext; }; + var peg$f56 = function() { return "perDiem"; }; + var peg$f57 = function() { return "drafts"; }; + var peg$f58 = function() { return "originalamount"; }; + var peg$f59 = function() { return "taxAmount"; }; + var peg$f60 = function() { return "taxrate"; }; + var peg$f61 = function() { return "policyname"; }; + var peg$f62 = function() { return "withdrawalID"; }; + var peg$f63 = function() { return "bankAccount"; }; + var peg$f64 = function() { return "reportID"; }; + var peg$f65 = function() { return "base62ReportID"; }; + var peg$f66 = function() { return "exportedto"; }; + var peg$f67 = function() { return "exchangeRate"; }; + var peg$f68 = function() { return "reimbursableTotal"; }; + var peg$f69 = function() { return "nonReimbursableTotal"; }; + var peg$f70 = function() { return "groupFrom"; }; + var peg$f71 = function() { return "groupExpenses"; }; + var peg$f72 = function() { return "groupTotal"; }; + var peg$f73 = function() { return "groupCard"; }; + var peg$f74 = function() { return "groupFeed"; }; + var peg$f75 = function() { return "groupBankAccount"; }; + var peg$f76 = function() { return "groupWithdrawn"; }; + var peg$f77 = function() { return "groupWithdrawalID"; }; + var peg$f78 = function() { return "eq"; }; + var peg$f79 = function() { return "neq"; }; + var peg$f80 = function() { return "gte"; }; + var peg$f81 = function() { return "gt"; }; + var peg$f82 = function() { return "lte"; }; + var peg$f83 = function() { return "lt"; }; + var peg$f84 = function(o) { if (nameOperator) { expectingNestedQuote = (o === "eq"); // Use simple parser if no valid operator is found } isColumnsContext = false; return o; }; - var peg$f84 = function(chars) { return chars.join("").trim(); }; - var peg$f85 = function() { + var peg$f85 = function(chars) { return chars.join("").trim(); }; + var peg$f86 = function() { isColumnsContext = false; return "and"; }; - var peg$f86 = function() { return expectingNestedQuote; }; - var peg$f87 = function(start, inner, end) { //handle no-breaking space + var peg$f87 = function() { return expectingNestedQuote; }; + var peg$f88 = function(start, inner, end) { //handle no-breaking space return [...start, '"', ...inner, '"', ...end].join(""); }; - var peg$f88 = function(start) {return "“"}; - var peg$f89 = function(start) {return "”"}; - var peg$f90 = function(start) {return "\""}; - var peg$f91 = function(start, inner, end) { + var peg$f89 = function(start) {return "“"}; + var peg$f90 = function(start) {return "”"}; + var peg$f91 = function(start) {return "\""}; + var peg$f92 = function(start, inner, end) { return [...start, '"', ...inner, '"'].join(""); }; var peg$currPos = options.peg$currPos | 0; @@ -1235,6 +1238,9 @@ function peg$parse(input, options) { s1 = peg$parsegroupBy(); if (s1 === peg$FAILED) { s1 = peg$parsecolumns(); + if (s1 === peg$FAILED) { + s1 = peg$parselimit(); + } } } } @@ -2178,13 +2184,13 @@ function peg$parse(input, options) { return s0; } - function peg$parsefeed() { + function peg$parselimit() { var s0, s1; s0 = peg$currPos; - s1 = input.substr(peg$currPos, 4); + s1 = input.substr(peg$currPos, 5); if (s1.toLowerCase() === peg$c50) { - peg$currPos += 4; + peg$currPos += 5; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e55); } @@ -2198,13 +2204,13 @@ function peg$parse(input, options) { return s0; } - function peg$parsetitle() { + function peg$parsefeed() { var s0, s1; s0 = peg$currPos; - s1 = input.substr(peg$currPos, 5); + s1 = input.substr(peg$currPos, 4); if (s1.toLowerCase() === peg$c51) { - peg$currPos += 5; + peg$currPos += 4; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e56); } @@ -2218,13 +2224,13 @@ function peg$parse(input, options) { return s0; } - function peg$parseassignee() { + function peg$parsetitle() { var s0, s1; s0 = peg$currPos; - s1 = input.substr(peg$currPos, 8); + s1 = input.substr(peg$currPos, 5); if (s1.toLowerCase() === peg$c52) { - peg$currPos += 8; + peg$currPos += 5; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e57); } @@ -2238,28 +2244,48 @@ function peg$parse(input, options) { return s0; } + function peg$parseassignee() { + var s0, s1; + + s0 = peg$currPos; + s1 = input.substr(peg$currPos, 8); + if (s1.toLowerCase() === peg$c53) { + peg$currPos += 8; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e58); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f46(); + } + s0 = s1; + + return s0; + } + function peg$parsecreatedBy() { var s0, s1; s0 = input.substr(peg$currPos, 9); - if (s0.toLowerCase() === peg$c53) { + if (s0.toLowerCase() === peg$c54) { peg$currPos += 9; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e58); } + if (peg$silentFails === 0) { peg$fail(peg$e59); } } if (s0 === peg$FAILED) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 10); - if (s1.toLowerCase() === peg$c54) { + if (s1.toLowerCase() === peg$c55) { peg$currPos += 10; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e59); } + if (peg$silentFails === 0) { peg$fail(peg$e60); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f46(); + s1 = peg$f47(); } s0 = s1; } @@ -2272,15 +2298,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 6); - if (s1.toLowerCase() === peg$c55) { + if (s1.toLowerCase() === peg$c56) { peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e60); } + if (peg$silentFails === 0) { peg$fail(peg$e61); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f47(); + s1 = peg$f48(); } s0 = s1; @@ -2292,15 +2318,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 5); - if (s1.toLowerCase() === peg$c56) { + if (s1.toLowerCase() === peg$c57) { peg$currPos += 5; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e61); } + if (peg$silentFails === 0) { peg$fail(peg$e62); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f48(); + s1 = peg$f49(); } s0 = s1; @@ -2312,15 +2338,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 3); - if (s1.toLowerCase() === peg$c57) { + if (s1.toLowerCase() === peg$c58) { peg$currPos += 3; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e63); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f49(); + s1 = peg$f50(); } s0 = s1; @@ -2332,15 +2358,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 2); - if (s1.toLowerCase() === peg$c58) { + if (s1.toLowerCase() === peg$c59) { peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e63); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f50(); + s1 = peg$f51(); } s0 = s1; @@ -2351,24 +2377,24 @@ function peg$parse(input, options) { var s0, s1; s0 = input.substr(peg$currPos, 14); - if (s0.toLowerCase() === peg$c59) { + if (s0.toLowerCase() === peg$c60) { peg$currPos += 14; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e64); } + if (peg$silentFails === 0) { peg$fail(peg$e65); } } if (s0 === peg$FAILED) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 15); - if (s1.toLowerCase() === peg$c60) { + if (s1.toLowerCase() === peg$c61) { peg$currPos += 15; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e65); } + if (peg$silentFails === 0) { peg$fail(peg$e66); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f51(); + s1 = peg$f52(); } s0 = s1; } @@ -2380,24 +2406,24 @@ function peg$parse(input, options) { var s0, s1; s0 = input.substr(peg$currPos, 16); - if (s0.toLowerCase() === peg$c61) { + if (s0.toLowerCase() === peg$c62) { peg$currPos += 16; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e66); } + if (peg$silentFails === 0) { peg$fail(peg$e67); } } if (s0 === peg$FAILED) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 17); - if (s1.toLowerCase() === peg$c62) { + if (s1.toLowerCase() === peg$c63) { peg$currPos += 17; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e67); } + if (peg$silentFails === 0) { peg$fail(peg$e68); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f52(); + s1 = peg$f53(); } s0 = s1; } @@ -2410,15 +2436,15 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 7); - if (s1.toLowerCase() === peg$c63) { + if (s1.toLowerCase() === peg$c64) { peg$currPos += 7; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e68); } + if (peg$silentFails === 0) { peg$fail(peg$e69); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f53(); + s1 = peg$f54(); } s0 = s1; @@ -2430,7 +2456,7 @@ function peg$parse(input, options) { s0 = peg$currPos; peg$savedPos = peg$currPos; - s1 = peg$f54(); + s1 = peg$f55(); if (s1) { s1 = undefined; } else { @@ -2529,11 +2555,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 8); - if (s1.toLowerCase() === peg$c64) { + if (s1.toLowerCase() === peg$c65) { peg$currPos += 8; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e69); } + if (peg$silentFails === 0) { peg$fail(peg$e70); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2548,7 +2574,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f55(); + s0 = peg$f56(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2566,19 +2592,19 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 6); - if (s1.toLowerCase() === peg$c65) { + if (s1.toLowerCase() === peg$c66) { peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e70); } + if (peg$silentFails === 0) { peg$fail(peg$e71); } } if (s1 === peg$FAILED) { s1 = input.substr(peg$currPos, 5); - if (s1.toLowerCase() === peg$c66) { + if (s1.toLowerCase() === peg$c67) { peg$currPos += 5; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e71); } + if (peg$silentFails === 0) { peg$fail(peg$e72); } } } if (s1 !== peg$FAILED) { @@ -2594,7 +2620,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f56(); + s0 = peg$f57(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2612,11 +2638,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 15); - if (s1.toLowerCase() === peg$c67) { + if (s1.toLowerCase() === peg$c68) { peg$currPos += 15; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e72); } + if (peg$silentFails === 0) { peg$fail(peg$e73); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2631,7 +2657,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f57(); + s0 = peg$f58(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2649,11 +2675,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 3); - if (s1.toLowerCase() === peg$c68) { + if (s1.toLowerCase() === peg$c69) { peg$currPos += 3; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e73); } + if (peg$silentFails === 0) { peg$fail(peg$e74); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2668,7 +2694,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f58(); + s0 = peg$f59(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2705,7 +2731,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f59(); + s0 = peg$f60(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2723,11 +2749,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 11); - if (s1.toLowerCase() === peg$c69) { + if (s1.toLowerCase() === peg$c70) { peg$currPos += 11; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e74); } + if (peg$silentFails === 0) { peg$fail(peg$e75); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2742,7 +2768,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f60(); + s0 = peg$f61(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2779,7 +2805,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f61(); + s0 = peg$f62(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2797,11 +2823,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 12); - if (s1.toLowerCase() === peg$c70) { + if (s1.toLowerCase() === peg$c71) { peg$currPos += 12; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e75); } + if (peg$silentFails === 0) { peg$fail(peg$e76); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2816,7 +2842,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f62(); + s0 = peg$f63(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2834,11 +2860,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 14); - if (s1.toLowerCase() === peg$c71) { + if (s1.toLowerCase() === peg$c72) { peg$currPos += 14; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e76); } + if (peg$silentFails === 0) { peg$fail(peg$e77); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2853,7 +2879,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f63(); + s0 = peg$f64(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2890,7 +2916,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f64(); + s0 = peg$f65(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2908,11 +2934,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 11); - if (s1.toLowerCase() === peg$c72) { + if (s1.toLowerCase() === peg$c73) { peg$currPos += 11; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e77); } + if (peg$silentFails === 0) { peg$fail(peg$e78); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2927,7 +2953,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f65(); + s0 = peg$f66(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2945,11 +2971,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 13); - if (s1.toLowerCase() === peg$c73) { + if (s1.toLowerCase() === peg$c74) { peg$currPos += 13; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e78); } + if (peg$silentFails === 0) { peg$fail(peg$e79); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2964,7 +2990,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f66(); + s0 = peg$f67(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2982,11 +3008,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 18); - if (s1.toLowerCase() === peg$c74) { + if (s1.toLowerCase() === peg$c75) { peg$currPos += 18; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e79); } + if (peg$silentFails === 0) { peg$fail(peg$e80); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3001,7 +3027,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f67(); + s0 = peg$f68(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3019,11 +3045,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 22); - if (s1.toLowerCase() === peg$c75) { + if (s1.toLowerCase() === peg$c76) { peg$currPos += 22; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e81); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3038,7 +3064,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f68(); + s0 = peg$f69(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3056,11 +3082,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 10); - if (s1.toLowerCase() === peg$c76) { + if (s1.toLowerCase() === peg$c77) { peg$currPos += 10; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e81); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3075,7 +3101,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f69(); + s0 = peg$f70(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3093,11 +3119,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 14); - if (s1.toLowerCase() === peg$c77) { + if (s1.toLowerCase() === peg$c78) { peg$currPos += 14; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e82); } + if (peg$silentFails === 0) { peg$fail(peg$e83); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3112,7 +3138,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f70(); + s0 = peg$f71(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3130,11 +3156,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 11); - if (s1.toLowerCase() === peg$c78) { + if (s1.toLowerCase() === peg$c79) { peg$currPos += 11; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e83); } + if (peg$silentFails === 0) { peg$fail(peg$e84); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3149,7 +3175,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f71(); + s0 = peg$f72(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3167,11 +3193,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 10); - if (s1.toLowerCase() === peg$c79) { + if (s1.toLowerCase() === peg$c80) { peg$currPos += 10; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e84); } + if (peg$silentFails === 0) { peg$fail(peg$e85); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3186,7 +3212,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f72(); + s0 = peg$f73(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3204,11 +3230,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 10); - if (s1.toLowerCase() === peg$c80) { + if (s1.toLowerCase() === peg$c81) { peg$currPos += 10; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e85); } + if (peg$silentFails === 0) { peg$fail(peg$e86); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3223,7 +3249,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f73(); + s0 = peg$f74(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3241,11 +3267,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 18); - if (s1.toLowerCase() === peg$c81) { + if (s1.toLowerCase() === peg$c82) { peg$currPos += 18; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e86); } + if (peg$silentFails === 0) { peg$fail(peg$e87); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3260,7 +3286,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f74(); + s0 = peg$f75(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3278,11 +3304,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 15); - if (s1.toLowerCase() === peg$c82) { + if (s1.toLowerCase() === peg$c83) { peg$currPos += 15; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e87); } + if (peg$silentFails === 0) { peg$fail(peg$e88); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3297,7 +3323,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f75(); + s0 = peg$f76(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3315,11 +3341,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.substr(peg$currPos, 19); - if (s1.toLowerCase() === peg$c83) { + if (s1.toLowerCase() === peg$c84) { peg$currPos += 19; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e88); } + if (peg$silentFails === 0) { peg$fail(peg$e89); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3334,7 +3360,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f76(); + s0 = peg$f77(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3357,81 +3383,81 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e90); } + if (peg$silentFails === 0) { peg$fail(peg$e91); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f77(); + s1 = peg$f78(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c84) { - s1 = peg$c84; + if (input.substr(peg$currPos, 2) === peg$c85) { + s1 = peg$c85; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e91); } + if (peg$silentFails === 0) { peg$fail(peg$e92); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f78(); + s1 = peg$f79(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c85) { - s1 = peg$c85; + if (input.substr(peg$currPos, 2) === peg$c86) { + s1 = peg$c86; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e92); } + if (peg$silentFails === 0) { peg$fail(peg$e93); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f79(); + s1 = peg$f80(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c86; + s1 = peg$c87; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e93); } + if (peg$silentFails === 0) { peg$fail(peg$e94); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f80(); + s1 = peg$f81(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c87) { - s1 = peg$c87; + if (input.substr(peg$currPos, 2) === peg$c88) { + s1 = peg$c88; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e94); } + if (peg$silentFails === 0) { peg$fail(peg$e95); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f81(); + s1 = peg$f82(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c88; + s1 = peg$c89; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e95); } + if (peg$silentFails === 0) { peg$fail(peg$e96); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f82(); + s1 = peg$f83(); } s0 = s1; } @@ -3442,7 +3468,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e89); } + if (peg$silentFails === 0) { peg$fail(peg$e90); } } return s0; @@ -3455,7 +3481,7 @@ function peg$parse(input, options) { s1 = peg$parseoperator(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f83(s1); + s1 = peg$f84(s1); } s0 = s1; @@ -3473,7 +3499,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e97); } + if (peg$silentFails === 0) { peg$fail(peg$e98); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { @@ -3483,7 +3509,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e97); } + if (peg$silentFails === 0) { peg$fail(peg$e98); } } } } else { @@ -3491,13 +3517,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f84(s1); + s1 = peg$f85(s1); } s0 = s1; peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e96); } + if (peg$silentFails === 0) { peg$fail(peg$e97); } } return s0; @@ -3509,7 +3535,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$parse_(); peg$savedPos = s0; - s1 = peg$f85(); + s1 = peg$f86(); s0 = s1; return s0; @@ -3525,7 +3551,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e99); } + if (peg$silentFails === 0) { peg$fail(peg$e100); } } while (s1 !== peg$FAILED) { s0.push(s1); @@ -3534,12 +3560,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e99); } + if (peg$silentFails === 0) { peg$fail(peg$e100); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e98); } + if (peg$silentFails === 0) { peg$fail(peg$e99); } return s0; } @@ -3549,7 +3575,7 @@ function peg$parse(input, options) { s0 = peg$currPos; peg$savedPos = peg$currPos; - s1 = peg$f86(); + s1 = peg$f87(); if (s1) { s1 = undefined; } else { @@ -3586,7 +3612,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e101); } + if (peg$silentFails === 0) { peg$fail(peg$e102); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -3595,7 +3621,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e101); } + if (peg$silentFails === 0) { peg$fail(peg$e102); } } } s2 = input.charAt(peg$currPos); @@ -3603,7 +3629,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e102); } + if (peg$silentFails === 0) { peg$fail(peg$e103); } } if (s2 !== peg$FAILED) { s3 = []; @@ -3612,7 +3638,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e103); } + if (peg$silentFails === 0) { peg$fail(peg$e104); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -3621,7 +3647,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e103); } + if (peg$silentFails === 0) { peg$fail(peg$e104); } } } s4 = input.charAt(peg$currPos); @@ -3629,7 +3655,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e102); } + if (peg$silentFails === 0) { peg$fail(peg$e103); } } if (s4 !== peg$FAILED) { s5 = []; @@ -3638,7 +3664,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e97); } + if (peg$silentFails === 0) { peg$fail(peg$e98); } } while (s6 !== peg$FAILED) { s5.push(s6); @@ -3647,11 +3673,11 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e97); } + if (peg$silentFails === 0) { peg$fail(peg$e98); } } } peg$savedPos = s0; - s0 = peg$f87(s1, s3, s5); + s0 = peg$f88(s1, s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3663,7 +3689,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e100); } + if (peg$silentFails === 0) { peg$fail(peg$e101); } } return s0; @@ -3680,7 +3706,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e101); } + if (peg$silentFails === 0) { peg$fail(peg$e102); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -3689,7 +3715,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e101); } + if (peg$silentFails === 0) { peg$fail(peg$e102); } } } s2 = input.charAt(peg$currPos); @@ -3697,7 +3723,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e102); } + if (peg$silentFails === 0) { peg$fail(peg$e103); } } if (s2 !== peg$FAILED) { s3 = []; @@ -3706,7 +3732,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e103); } + if (peg$silentFails === 0) { peg$fail(peg$e104); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -3722,15 +3748,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c89; + s6 = peg$c90; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e104); } + if (peg$silentFails === 0) { peg$fail(peg$e105); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f88(s1); + s4 = peg$f89(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3753,15 +3779,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c90; + s6 = peg$c91; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e105); } + if (peg$silentFails === 0) { peg$fail(peg$e106); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f89(s1); + s4 = peg$f90(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3784,15 +3810,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c91; + s6 = peg$c92; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e106); } + if (peg$silentFails === 0) { peg$fail(peg$e107); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f90(s1); + s4 = peg$f91(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3811,7 +3837,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e103); } + if (peg$silentFails === 0) { peg$fail(peg$e104); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -3827,15 +3853,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c89; + s6 = peg$c90; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e104); } + if (peg$silentFails === 0) { peg$fail(peg$e105); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f88(s1); + s4 = peg$f89(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3858,15 +3884,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c90; + s6 = peg$c91; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e105); } + if (peg$silentFails === 0) { peg$fail(peg$e106); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f89(s1); + s4 = peg$f90(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3889,15 +3915,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c91; + s6 = peg$c92; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e106); } + if (peg$silentFails === 0) { peg$fail(peg$e107); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f90(s1); + s4 = peg$f91(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -3913,7 +3939,7 @@ function peg$parse(input, options) { s4 = peg$parseclosingQuote(); if (s4 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f91(s1, s3, s4); + s0 = peg$f92(s1, s3, s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3925,7 +3951,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e100); } + if (peg$silentFails === 0) { peg$fail(peg$e101); } } return s0; @@ -3940,7 +3966,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e102); } + if (peg$silentFails === 0) { peg$fail(peg$e103); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -3978,7 +4004,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e107); } + if (peg$silentFails === 0) { peg$fail(peg$e108); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -3987,7 +4013,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e107); } + if (peg$silentFails === 0) { peg$fail(peg$e108); } } } s2 = []; @@ -3996,7 +4022,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e108); } + if (peg$silentFails === 0) { peg$fail(peg$e109); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -4005,7 +4031,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e108); } + if (peg$silentFails === 0) { peg$fail(peg$e109); } } } s3 = []; @@ -4014,7 +4040,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e109); } + if (peg$silentFails === 0) { peg$fail(peg$e110); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -4023,7 +4049,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e109); } + if (peg$silentFails === 0) { peg$fail(peg$e110); } } } s4 = peg$parseoperator(); @@ -4042,7 +4068,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e110); } + if (peg$silentFails === 0) { peg$fail(peg$e111); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -4051,7 +4077,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e110); } + if (peg$silentFails === 0) { peg$fail(peg$e111); } } } s2 = peg$currPos; @@ -4098,7 +4124,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e111); } + if (peg$silentFails === 0) { peg$fail(peg$e112); } } } } @@ -4114,7 +4140,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e112); } + if (peg$silentFails === 0) { peg$fail(peg$e113); } } if (s0 === peg$FAILED) { s0 = peg$currPos; @@ -4164,7 +4190,7 @@ function peg$parse(input, options) { // List fields where you cannot prefix it with "-" to negate it const nonNegatableKeys = new Set([ - "type", "keyword", "groupCurrency", "groupBy", "columns" + "type", "keyword", "groupCurrency", "groupBy", "columns", "limit" ]); function isDefaultSortValue(sortBy) { diff --git a/src/libs/SearchParser/searchParser.peggy b/src/libs/SearchParser/searchParser.peggy index a0301ee29ee21..b93aaf1c4c680 100644 --- a/src/libs/SearchParser/searchParser.peggy +++ b/src/libs/SearchParser/searchParser.peggy @@ -53,7 +53,7 @@ // List fields where you cannot prefix it with "-" to negate it const nonNegatableKeys = new Set([ - "type", "keyword", "groupCurrency", "groupBy", "columns" + "type", "keyword", "groupCurrency", "groupBy", "columns", "limit" ]); function isDefaultSortValue(sortBy) { @@ -260,7 +260,7 @@ filterKey return k; } -defaultKey "default key" = @(type / status / sortBy / sortOrder / policyID / groupBy / columns) +defaultKey "default key" = @(type / status / sortBy / sortOrder / policyID / groupBy / columns / limit) identifier = (","+)? parts:(values / quotedString / alphanumeric)|1.., ","+| empty:(","+)? { diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index cd1652b59ad92..04268075790d4 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -93,7 +93,9 @@ const keyToUserFriendlyMap = createKeyToUserFriendlyMap(); * @example * getUserFriendlyKey("taxRate") // returns "tax-rate" */ -function getUserFriendlyKey(keyName: SearchFilterKey | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER): UserFriendlyKey { +function getUserFriendlyKey( + keyName: SearchFilterKey | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT, +): UserFriendlyKey { const isReportField = keyName.startsWith(CONST.SEARCH.REPORT_FIELD.GLOBAL_PREFIX); if (isReportField) { @@ -375,6 +377,7 @@ function getQueryHashes(query: SearchQueryJSON): {primaryHash: number; recentSea orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY}:${query.sortBy}`; orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER}:${query.sortOrder}`; orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.COLUMNS}:${Array.isArray(query.columns) ? query.columns.join(',') : query.columns}`; + orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT}:${query.limit ?? ''}`; if (query.policyID) { orderedQuery += ` ${CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID}:${Array.isArray(query.policyID) ? query.policyID.join(',') : query.policyID} `; @@ -442,6 +445,11 @@ function buildSearchQueryJSON(query: SearchQueryString, rawQuery?: SearchQuerySt result.policyID = [result.policyID]; } + if (result.limit !== undefined) { + const num = Number(result.limit); + result.limit = Number.isInteger(num) && num > 0 ? num : undefined; + } + return result; } catch (e) { console.error(`Error when parsing SearchQuery: "${query}"`, e); @@ -545,6 +553,7 @@ function getSanitizedRawFilters(queryJSON: SearchQueryJSON): RawQueryFilter[] | type BuildQueryStringOptions = { sortBy?: string; sortOrder?: string; + limit?: number; }; /** @@ -573,6 +582,9 @@ function buildQueryStringFromFilterFormValues(filterValues: Partial 0) { const segments: string[] = []; @@ -1269,6 +1284,10 @@ function buildUserReadableQueryString( title += ` columns:${columnValue}`; } + if (limit !== undefined) { + title += ` limit:${limit}`; + } + for (const filterObject of filters) { const key = filterObject.key; const displayQueryFilters = getDisplayQueryFiltersForKey(key, filterObject.filters, PersonalDetails, reports, taxRates, cardList, cardFeeds, policies, currentUserAccountID); diff --git a/tests/unit/Search/SearchQueryUtilsTest.ts b/tests/unit/Search/SearchQueryUtilsTest.ts index 2e3b935d15f63..edd2878c5e34a 100644 --- a/tests/unit/Search/SearchQueryUtilsTest.ts +++ b/tests/unit/Search/SearchQueryUtilsTest.ts @@ -268,6 +268,39 @@ describe('SearchQueryUtils', () => { expect(result).toEqual('sortBy:date sortOrder:desc type:expense withdrawn:last-month'); }); + + describe('limit option', () => { + test('includes limit in query string when provided', () => { + const filterValues: Partial = { + type: 'expense', + }; + + const result = buildQueryStringFromFilterFormValues(filterValues, {limit: 10}); + + expect(result).toEqual('sortBy:date sortOrder:desc limit:10 type:expense'); + }); + + test('combines limit with sort options', () => { + const filterValues: Partial = { + type: 'expense', + merchant: 'Amazon', + }; + + const result = buildQueryStringFromFilterFormValues(filterValues, {sortBy: 'amount', sortOrder: 'asc', limit: 25}); + + expect(result).toEqual('sortBy:amount sortOrder:asc limit:25 type:expense merchant:Amazon'); + }); + + test('omits limit when not provided', () => { + const filterValues: Partial = { + type: 'expense', + }; + + const result = buildQueryStringFromFilterFormValues(filterValues); + + expect(result).not.toContain('limit:'); + }); + }); }); describe('buildUserReadableQueryString', () => { @@ -559,6 +592,50 @@ describe('SearchQueryUtils', () => { expect(queryJSONa?.similarSearchHash).not.toEqual(queryJSONb?.similarSearchHash); }); + + describe('limit filter hashing', () => { + it('should return same similarSearchHash for queries with different limit values', () => { + const queryJSONa = buildSearchQueryJSON('type:expense limit:10'); + const queryJSONb = buildSearchQueryJSON('type:expense limit:50'); + + expect(queryJSONa?.similarSearchHash).toEqual(queryJSONb?.similarSearchHash); + }); + + it('should return different primaryHash for queries with different limit values', () => { + const queryJSONa = buildSearchQueryJSON('type:expense limit:10'); + const queryJSONb = buildSearchQueryJSON('type:expense limit:50'); + + expect(queryJSONa?.hash).not.toEqual(queryJSONb?.hash); + }); + }); + }); + + describe('limit filter parsing', () => { + it('parses limit value as a number', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:25'); + + expect(queryJSON?.limit).toBe(25); + expect(typeof queryJSON?.limit).toBe('number'); + }); + + it('preserves limit when combined with other filters', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:100 merchant:Amazon'); + + expect(queryJSON?.limit).toBe(100); + expect(queryJSON?.type).toBe('expense'); + }); + + it('returns undefined limit when not specified in query', () => { + const queryJSON = buildSearchQueryJSON('type:expense merchant:Amazon'); + + expect(queryJSON?.limit).toBeUndefined(); + }); + + it('handles large limit values', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:9999'); + + expect(queryJSON?.limit).toBe(9999); + }); }); describe('getFilterDisplayValue', () => { diff --git a/tests/unit/SearchAutocompleteParserTest.ts b/tests/unit/SearchAutocompleteParserTest.ts index 256cf6ed89212..be6e703e08c96 100644 --- a/tests/unit/SearchAutocompleteParserTest.ts +++ b/tests/unit/SearchAutocompleteParserTest.ts @@ -299,6 +299,45 @@ const tests = [ }, ]; +const limitAutocompleteTests = [ + { + description: 'basic limit filter autocomplete', + query: 'limit:10', + expected: { + autocomplete: {key: 'limit', value: '10', negated: false, start: 6, length: 2}, + ranges: [{key: 'limit', value: '10', negated: false, start: 6, length: 2}], + }, + }, + { + description: 'empty limit value shows autocomplete suggestion', + query: 'limit:', + expected: { + autocomplete: {key: 'limit', value: '', start: 6, length: 0, negated: false}, + ranges: [], + }, + }, + { + description: 'limit filter in complex query', + query: 'type:expense limit:100 merchant:test', + expected: { + autocomplete: {key: 'merchant', value: 'test', negated: false, start: 32, length: 4}, + ranges: [ + {key: 'type', value: 'expense', negated: false, start: 5, length: 7}, + {key: 'limit', value: '100', negated: false, start: 19, length: 3}, + {key: 'merchant', value: 'test', negated: false, start: 32, length: 4}, + ], + }, + }, + { + description: 'limit filter is case-insensitive', + query: 'LIMIT:50', + expected: { + autocomplete: {key: 'limit', value: '50', negated: false, start: 6, length: 2}, + ranges: [{key: 'limit', value: '50', negated: false, start: 6, length: 2}], + }, + }, +]; + const nameFieldContinuationTests = [ { query: 'to:John Smi', @@ -705,3 +744,11 @@ describe('autocomplete parser - name field continuation detection', () => { expect(result).toEqual(expected); }); }); + +describe('autocomplete parser - limit filter', () => { + test.each(limitAutocompleteTests)('$description: $query', ({query, expected}) => { + const result = parse(query) as SearchQueryJSON; + + expect(result).toEqual(expected); + }); +}); diff --git a/tests/unit/SearchAutocompleteUtilsTest.ts b/tests/unit/SearchAutocompleteUtilsTest.ts index e26c17fc371c5..692c35a4e61f6 100644 --- a/tests/unit/SearchAutocompleteUtilsTest.ts +++ b/tests/unit/SearchAutocompleteUtilsTest.ts @@ -208,6 +208,60 @@ describe('SearchAutocompleteUtils', () => { expect(result).toEqual([]); }); + describe('limit filter highlighting', () => { + it('highlights valid positive integer', () => { + const input = 'limit:10'; + + const result = parseForLiveMarkdown(input, currentUserName, mockSubstitutionMap, mockUserLogins, mockCurrencyList, mockCategoryList, mockTagList); + + expect(result).toEqual([{start: 6, type: 'mention-user', length: 2}]); + }); + + it('highlights larger limit values', () => { + const input = 'limit:100'; + + const result = parseForLiveMarkdown(input, currentUserName, mockSubstitutionMap, mockUserLogins, mockCurrencyList, mockCategoryList, mockTagList); + + expect(result).toEqual([{start: 6, type: 'mention-user', length: 3}]); + }); + + it('does not highlight zero value', () => { + const input = 'limit:0'; + + const result = parseForLiveMarkdown(input, currentUserName, mockSubstitutionMap, mockUserLogins, mockCurrencyList, mockCategoryList, mockTagList); + + expect(result).toEqual([]); + }); + + it('does not highlight non-integer value', () => { + const input = 'limit:10.5'; + + const result = parseForLiveMarkdown(input, currentUserName, mockSubstitutionMap, mockUserLogins, mockCurrencyList, mockCategoryList, mockTagList); + + expect(result).toEqual([]); + }); + + it('does not highlight negative value', () => { + const input = 'limit:-5'; + + const result = parseForLiveMarkdown(input, currentUserName, mockSubstitutionMap, mockUserLogins, mockCurrencyList, mockCategoryList, mockTagList); + + expect(result).toEqual([]); + }); + + it('highlights limit in complex query with other filters', () => { + const input = 'type:expense limit:50 currency:USD'; + + const result = parseForLiveMarkdown(input, currentUserName, mockSubstitutionMap, mockUserLogins, mockCurrencyList, mockCategoryList, mockTagList); + + expect(result).toEqual([ + {start: 5, type: 'mention-user', length: 7}, // type:expense + {start: 19, type: 'mention-user', length: 2}, // limit:50 + {start: 31, type: 'mention-user', length: 3}, // currency:USD + ]); + }); + }); + it('should handle valid AMOUNT filters but not invalid TOTAL amounts', () => { const input = 'amount:-50.25'; diff --git a/tests/unit/SearchParserTest.ts b/tests/unit/SearchParserTest.ts index 32d7b6d79c694..8683737ad4ce9 100644 --- a/tests/unit/SearchParserTest.ts +++ b/tests/unit/SearchParserTest.ts @@ -832,6 +832,65 @@ const keywordTests = [ }, ]; +const limitTests = [ + { + description: 'basic limit filter', + query: 'type:expense limit:10', + expected: { + type: 'expense', + status: CONST.SEARCH.STATUS.EXPENSE.ALL, + sortBy: 'date', + sortOrder: 'desc', + limit: '10', + filters: null, + }, + }, + { + description: 'limit filter combined with other filters', + query: 'type:expense limit:50 merchant:Amazon', + expected: { + type: 'expense', + status: CONST.SEARCH.STATUS.EXPENSE.ALL, + sortBy: 'date', + sortOrder: 'desc', + limit: '50', + filters: { + operator: 'eq', + left: 'merchant', + right: 'Amazon', + }, + }, + }, + { + description: 'limit filter is case-insensitive', + query: 'type:expense LIMIT:25', + expected: { + type: 'expense', + status: CONST.SEARCH.STATUS.EXPENSE.ALL, + sortBy: 'date', + sortOrder: 'desc', + limit: '25', + filters: null, + }, + }, + { + description: 'limit filter at the beginning of query', + query: 'limit:100 category:travel,hotel', + expected: { + type: 'expense', + status: CONST.SEARCH.STATUS.EXPENSE.ALL, + sortBy: 'date', + sortOrder: 'desc', + limit: '100', + filters: { + operator: 'eq', + left: 'category', + right: ['travel', 'hotel'], + }, + }, + }, +]; + describe('search parser', () => { test.each(tests)(`parsing: $query`, ({query, expected}) => { const {rawFilterList, ...resultWithoutRawFilters} = parse(query) as SearchQueryJSON; @@ -845,3 +904,10 @@ describe('Testing search parser with special characters and wrapped in quotes.', expect(resultWithoutRawFilters).toEqual(expected); }); }); + +describe('search parser - limit filter', () => { + test.each(limitTests)('$description: $query', ({query, expected}) => { + const {rawFilterList, ...resultWithoutRawFilters} = parse(query) as SearchQueryJSON; + expect(resultWithoutRawFilters).toEqual(expected); + }); +}); From 4a5fcdafb308d5b24856c8fcaf25204bcf4133d1 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Thu, 22 Jan 2026 23:47:58 +0300 Subject: [PATCH 02/13] fix: only include limit in search hash when explicitly set --- src/libs/SearchQueryUtils.ts | 5 +- tests/unit/Search/SearchQueryUtilsTest.ts | 108 ++++++++++++++++++++++ tests/unit/SearchAutocompleteUtilsTest.ts | 16 ++-- 3 files changed, 120 insertions(+), 9 deletions(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 04268075790d4..02c1db10acb52 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -377,7 +377,10 @@ function getQueryHashes(query: SearchQueryJSON): {primaryHash: number; recentSea orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY}:${query.sortBy}`; orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER}:${query.sortOrder}`; orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.COLUMNS}:${Array.isArray(query.columns) ? query.columns.join(',') : query.columns}`; - orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT}:${query.limit ?? ''}`; + + if (query.limit !== undefined) { + orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT}:${query.limit}`; + } if (query.policyID) { orderedQuery += ` ${CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID}:${Array.isArray(query.policyID) ? query.policyID.join(',') : query.policyID} `; diff --git a/tests/unit/Search/SearchQueryUtilsTest.ts b/tests/unit/Search/SearchQueryUtilsTest.ts index edd2878c5e34a..d62600d09d500 100644 --- a/tests/unit/Search/SearchQueryUtilsTest.ts +++ b/tests/unit/Search/SearchQueryUtilsTest.ts @@ -387,6 +387,43 @@ describe('SearchQueryUtils', () => { expect(merchantFilter?.value).toBe('Lyft'); }); + + test('includes limit in readable query string when present', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:25'); + + if (!queryJSON) { + throw new Error('Failed to parse query string'); + } + + const result = buildUserReadableQueryString(queryJSON, undefined, emptyReports, emptyTaxRates, emptyCardList, emptyCardFeeds, emptyPolicies, currentUserAccountID); + + expect(result).toContain('limit:25'); + }); + + test('does not include limit in readable query string when not specified', () => { + const queryJSON = buildSearchQueryJSON('type:expense merchant:Test'); + + if (!queryJSON) { + throw new Error('Failed to parse query string'); + } + + const result = buildUserReadableQueryString(queryJSON, undefined, emptyReports, emptyTaxRates, emptyCardList, emptyCardFeeds, emptyPolicies, currentUserAccountID); + + expect(result).not.toContain('limit:'); + }); + + test('includes limit with other root parameters in readable query string', () => { + const queryJSON = buildSearchQueryJSON('type:expense groupBy:category limit:50'); + + if (!queryJSON) { + throw new Error('Failed to parse query string'); + } + + const result = buildUserReadableQueryString(queryJSON, undefined, emptyReports, emptyTaxRates, emptyCardList, emptyCardFeeds, emptyPolicies, currentUserAccountID); + + expect(result).toContain('limit:50'); + expect(result).toContain('group-by:category'); + }); }); describe('buildFilterFormValuesFromQuery', () => { @@ -607,6 +644,34 @@ describe('SearchQueryUtils', () => { expect(queryJSONa?.hash).not.toEqual(queryJSONb?.hash); }); + + it('should return same primaryHash for queries without limit (hash stability)', () => { + const queryJSONa = buildSearchQueryJSON('type:expense'); + const queryJSONb = buildSearchQueryJSON('type:expense'); + + expect(queryJSONa?.hash).toEqual(queryJSONb?.hash); + }); + + it('should return different primaryHash for query with valid limit vs without limit', () => { + const withoutLimit = buildSearchQueryJSON('type:expense'); + const withLimit = buildSearchQueryJSON('type:expense limit:10'); + + expect(withoutLimit?.hash).not.toEqual(withLimit?.hash); + }); + + it('should return same primaryHash for same limit value queried twice', () => { + const queryJSONa = buildSearchQueryJSON('type:expense limit:25'); + const queryJSONb = buildSearchQueryJSON('type:expense limit:25'); + + expect(queryJSONa?.hash).toEqual(queryJSONb?.hash); + }); + + it('should not include limit in hash when limit is not in query string', () => { + const queryJSON = buildSearchQueryJSON('type:expense merchant:test'); + + expect(queryJSON?.limit).toBeUndefined(); + expect(queryJSON?.hash).toBeDefined(); + }); }); }); @@ -636,6 +701,49 @@ describe('SearchQueryUtils', () => { expect(queryJSON?.limit).toBe(9999); }); + + it('converts limit:0 to undefined', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:0'); + + expect(queryJSON?.limit).toBeUndefined(); + }); + + it('converts negative limit to undefined', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:-10'); + + expect(queryJSON?.limit).toBeUndefined(); + }); + + it('converts decimal limit to undefined', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:10.5'); + + expect(queryJSON?.limit).toBeUndefined(); + }); + + it('converts non-numeric limit to undefined', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:abc'); + + expect(queryJSON?.limit).toBeUndefined(); + }); + + it('uses last limit value when multiple limits specified', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:10 limit:20'); + + expect(queryJSON?.limit).toBe(20); + }); + + it('treats empty limit as keyword, not limit filter', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:'); + + expect(queryJSON?.limit).toBeUndefined(); + }); + + it('treats negated limit as keyword since limit is non-negatable', () => { + const queryJSON = buildSearchQueryJSON('type:expense -limit:10'); + + expect(queryJSON?.limit).toBeUndefined(); + }); + }); describe('getFilterDisplayValue', () => { diff --git a/tests/unit/SearchAutocompleteUtilsTest.ts b/tests/unit/SearchAutocompleteUtilsTest.ts index 692c35a4e61f6..7b92ad879ee24 100644 --- a/tests/unit/SearchAutocompleteUtilsTest.ts +++ b/tests/unit/SearchAutocompleteUtilsTest.ts @@ -217,14 +217,6 @@ describe('SearchAutocompleteUtils', () => { expect(result).toEqual([{start: 6, type: 'mention-user', length: 2}]); }); - it('highlights larger limit values', () => { - const input = 'limit:100'; - - const result = parseForLiveMarkdown(input, currentUserName, mockSubstitutionMap, mockUserLogins, mockCurrencyList, mockCategoryList, mockTagList); - - expect(result).toEqual([{start: 6, type: 'mention-user', length: 3}]); - }); - it('does not highlight zero value', () => { const input = 'limit:0'; @@ -260,6 +252,14 @@ describe('SearchAutocompleteUtils', () => { {start: 31, type: 'mention-user', length: 3}, // currency:USD ]); }); + + it('does not highlight empty limit value', () => { + const input = 'limit:'; + + const result = parseForLiveMarkdown(input, currentUserName, mockSubstitutionMap, mockUserLogins, mockCurrencyList, mockCategoryList, mockTagList); + + expect(result).toEqual([]); + }); }); it('should handle valid AMOUNT filters but not invalid TOTAL amounts', () => { From a794eadccdb0c2917680037f8b34407c4f42cefb Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 23 Jan 2026 00:00:50 +0300 Subject: [PATCH 03/13] chore: run prettier --- tests/unit/Search/SearchQueryUtilsTest.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/Search/SearchQueryUtilsTest.ts b/tests/unit/Search/SearchQueryUtilsTest.ts index d62600d09d500..bbf0cd41f8cee 100644 --- a/tests/unit/Search/SearchQueryUtilsTest.ts +++ b/tests/unit/Search/SearchQueryUtilsTest.ts @@ -743,7 +743,6 @@ describe('SearchQueryUtils', () => { expect(queryJSON?.limit).toBeUndefined(); }); - }); describe('getFilterDisplayValue', () => { From daafee297663171a9b3c2f4df87e3eabdec30a45 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 23 Jan 2026 02:46:46 +0300 Subject: [PATCH 04/13] fix: Prevent limit from being dropped when modifying filters or columns --- .../Search/SearchAutocompleteList.tsx | 2 +- .../SearchPageHeader/SearchFiltersBar.tsx | 5 +++-- .../SearchRouter/getQueryWithSubstitutions.ts | 4 ++-- .../getUpdatedSubstitutionsMap.ts | 4 ++-- src/libs/SearchQueryUtils.ts | 20 ++++++++++-------- src/pages/Search/AdvancedSearchFilters.tsx | 21 +++++++++++++++++-- src/pages/Search/SearchColumnsPage.tsx | 9 ++++++-- tests/unit/Search/SearchQueryUtilsTest.ts | 12 +++++++++++ 8 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 4ae6c8dccbe44..fbce8d445e0ad 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -332,7 +332,7 @@ function SearchAutocompleteList({ if (!autocomplete && ranges.length > 0) { const lastRange = ranges.at(ranges.length - 1); - if (lastRange && CONTINUATION_DETECTION_SEARCH_FILTER_KEYS.includes(lastRange.key)) { + if (lastRange && CONTINUATION_DETECTION_SEARCH_FILTER_KEYS.includes(lastRange.key as SearchFilterKey)) { const afterLastRange = autocompleteQueryValue.substring(lastRange.start + lastRange.length); const continuationMatch = afterLastRange.match(/^\s+(\w+)/); diff --git a/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx b/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx index 41de08141f47c..82388b1bd11e7 100644 --- a/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx +++ b/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx @@ -307,10 +307,11 @@ function SearchFiltersBar({ updatedFilterFormValues.columns = []; } - // Preserve the current sortBy and sortOrder from queryJSON when updating filters + // Preserve the current sortBy, sortOrder, and limit from queryJSON when updating filters const queryString = buildQueryStringFromFilterFormValues(updatedFilterFormValues, { sortBy: queryJSON.sortBy, sortOrder: queryJSON.sortOrder, + limit: queryJSON.limit, }); close(() => { @@ -318,7 +319,7 @@ function SearchFiltersBar({ Navigation.setParams({q: queryString, rawQuery: undefined}); }); }, - [searchAdvancedFiltersForm, queryJSON.sortBy, queryJSON.sortOrder], + [searchAdvancedFiltersForm, queryJSON.sortBy, queryJSON.sortOrder, queryJSON.limit], ); const openAdvancedFilters = useCallback(() => { diff --git a/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts b/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts index 84895efb33a5b..794d26b108c56 100644 --- a/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts +++ b/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts @@ -1,10 +1,10 @@ -import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; +import type {SearchAutocompleteQueryRange, SearchAutocompleteRangeKey} from '@components/Search/types'; import {parse} from '@libs/SearchParser/autocompleteParser'; import {sanitizeSearchValue} from '@libs/SearchQueryUtils'; type SubstitutionMap = Record; -const getSubstitutionMapKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; +const getSubstitutionMapKey = (filterKey: SearchAutocompleteRangeKey, value: string) => `${filterKey}:${value}`; /** * Given a plaintext query and a SubstitutionMap object, this function will return a transformed query where: diff --git a/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts b/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts index 328eb3ff89814..d67cfce6b87cd 100644 --- a/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts +++ b/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts @@ -1,8 +1,8 @@ -import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; +import type {SearchAutocompleteQueryRange, SearchAutocompleteRangeKey} from '@components/Search/types'; import {parse} from '@libs/SearchParser/autocompleteParser'; import type {SubstitutionMap} from './getQueryWithSubstitutions'; -const getSubstitutionsKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; +const getSubstitutionsKey = (filterKey: SearchAutocompleteRangeKey, value: string) => `${filterKey}:${value}`; /** * Given a plaintext query and a SubstitutionMap object, diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index f5c63d85a4e3b..c941e4eb7c1bc 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -433,26 +433,28 @@ function buildSearchQueryJSON(query: SearchQueryString, rawQuery?: SearchQuerySt // Add the full input and hash to the results result.inputQuery = query; result.flatFilters = flatFilters; - const {primaryHash, recentSearchHash, similarSearchHash} = getQueryHashes(result); - result.hash = primaryHash; - result.recentSearchHash = recentSearchHash; - result.similarSearchHash = similarSearchHash; - - delete result.rawFilterList; - if (rawQuery) { - result.rawFilterList = getRawFilterListFromQuery(rawQuery); - } if (result.policyID && typeof result.policyID === 'string') { // Ensure policyID is always an array for consistency result.policyID = [result.policyID]; } + // Normalize limit before computing hashes to ensure invalid values don't affect hash if (result.limit !== undefined) { const num = Number(result.limit); result.limit = Number.isInteger(num) && num > 0 ? num : undefined; } + const {primaryHash, recentSearchHash, similarSearchHash} = getQueryHashes(result); + result.hash = primaryHash; + result.recentSearchHash = recentSearchHash; + result.similarSearchHash = similarSearchHash; + + delete result.rawFilterList; + if (rawQuery) { + result.rawFilterList = getRawFilterListFromQuery(rawQuery); + } + return result; } catch (e) { console.error(`Error when parsing SearchQuery: "${query}"`, e); diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 9e4725276527e..95f0fc5c7845a 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -29,7 +29,15 @@ import Navigation from '@libs/Navigation/Navigation'; import {createDisplayName} from '@libs/PersonalDetailsUtils'; import {getAllTaxRates, getCleanedTagName} from '@libs/PolicyUtils'; import {computeReportName} from '@libs/ReportNameUtils'; -import {buildCannedSearchQuery, buildQueryStringFromFilterFormValues, buildSearchQueryJSON, isCannedSearchQuery, isSearchDatePreset, sortOptionsWithEmptyValue} from '@libs/SearchQueryUtils'; +import { + buildCannedSearchQuery, + buildQueryStringFromFilterFormValues, + buildSearchQueryJSON, + getCurrentSearchQueryJSON, + isCannedSearchQuery, + isSearchDatePreset, + sortOptionsWithEmptyValue, +} from '@libs/SearchQueryUtils'; import {getExpenseTypeTranslationKey, getStatusOptions} from '@libs/SearchUIUtils'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; @@ -562,7 +570,16 @@ function AdvancedSearchFilters() { const {currentType, typeFiltersKeys} = useAdvancedSearchFilters(); - const queryString = useMemo(() => buildQueryStringFromFilterFormValues(searchAdvancedFilters), [searchAdvancedFilters]); + const currentQueryJSON = getCurrentSearchQueryJSON(); + const queryString = useMemo( + () => + buildQueryStringFromFilterFormValues(searchAdvancedFilters, { + sortBy: currentQueryJSON?.sortBy, + sortOrder: currentQueryJSON?.sortOrder, + limit: currentQueryJSON?.limit, + }), + [searchAdvancedFilters, currentQueryJSON?.sortBy, currentQueryJSON?.sortOrder, currentQueryJSON?.limit], + ); const queryJSON = useMemo(() => buildSearchQueryJSON(queryString || buildCannedSearchQuery()), [queryString]); const applyFiltersAndNavigate = () => { diff --git a/src/pages/Search/SearchColumnsPage.tsx b/src/pages/Search/SearchColumnsPage.tsx index a0e4b181d35d4..60bf746697168 100644 --- a/src/pages/Search/SearchColumnsPage.tsx +++ b/src/pages/Search/SearchColumnsPage.tsx @@ -17,7 +17,7 @@ import useOnyx from '@hooks/useOnyx'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import {buildQueryStringFromFilterFormValues} from '@libs/SearchQueryUtils'; +import {buildQueryStringFromFilterFormValues, getCurrentSearchQueryJSON} from '@libs/SearchQueryUtils'; import {getCustomColumnDefault, getCustomColumns, getSearchColumnTranslationKey} from '@libs/SearchUIUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -183,7 +183,12 @@ function SearchColumnsPage() { columns: selectedColumnIds, }; - const queryString = buildQueryStringFromFilterFormValues(updatedAdvancedFilters); + const currentQueryJSON = getCurrentSearchQueryJSON(); + const queryString = buildQueryStringFromFilterFormValues(updatedAdvancedFilters, { + sortBy: currentQueryJSON?.sortBy, + sortOrder: currentQueryJSON?.sortOrder, + limit: currentQueryJSON?.limit, + }); Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: queryString}), {forceReplace: true}); }; diff --git a/tests/unit/Search/SearchQueryUtilsTest.ts b/tests/unit/Search/SearchQueryUtilsTest.ts index bbf0cd41f8cee..e293a13807f9e 100644 --- a/tests/unit/Search/SearchQueryUtilsTest.ts +++ b/tests/unit/Search/SearchQueryUtilsTest.ts @@ -672,6 +672,18 @@ describe('SearchQueryUtils', () => { expect(queryJSON?.limit).toBeUndefined(); expect(queryJSON?.hash).toBeDefined(); }); + + it('should return same primaryHash for invalid limit as no limit (normalization before hashing)', () => { + const withoutLimit = buildSearchQueryJSON('type:expense'); + const withZeroLimit = buildSearchQueryJSON('type:expense limit:0'); + const withNegativeLimit = buildSearchQueryJSON('type:expense limit:-5'); + const withDecimalLimit = buildSearchQueryJSON('type:expense limit:10.5'); + + // All invalid limits should normalize to undefined and produce same hash as no limit + expect(withZeroLimit?.hash).toEqual(withoutLimit?.hash); + expect(withNegativeLimit?.hash).toEqual(withoutLimit?.hash); + expect(withDecimalLimit?.hash).toEqual(withoutLimit?.hash); + }); }); }); From 3dfa5afb5c7d77e7a72ae182d3778ad1b873a0bd Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 23 Jan 2026 02:52:55 +0300 Subject: [PATCH 05/13] fix: Add LIMIT to SearchFilterKey type and remove type assertions --- src/components/Search/SearchAutocompleteList.tsx | 2 +- .../Search/SearchRouter/getQueryWithSubstitutions.ts | 4 ++-- .../Search/SearchRouter/getUpdatedSubstitutionsMap.ts | 4 ++-- src/components/Search/types.ts | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index fbce8d445e0ad..4ae6c8dccbe44 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -332,7 +332,7 @@ function SearchAutocompleteList({ if (!autocomplete && ranges.length > 0) { const lastRange = ranges.at(ranges.length - 1); - if (lastRange && CONTINUATION_DETECTION_SEARCH_FILTER_KEYS.includes(lastRange.key as SearchFilterKey)) { + if (lastRange && CONTINUATION_DETECTION_SEARCH_FILTER_KEYS.includes(lastRange.key)) { const afterLastRange = autocompleteQueryValue.substring(lastRange.start + lastRange.length); const continuationMatch = afterLastRange.match(/^\s+(\w+)/); diff --git a/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts b/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts index 794d26b108c56..84895efb33a5b 100644 --- a/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts +++ b/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts @@ -1,10 +1,10 @@ -import type {SearchAutocompleteQueryRange, SearchAutocompleteRangeKey} from '@components/Search/types'; +import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; import {parse} from '@libs/SearchParser/autocompleteParser'; import {sanitizeSearchValue} from '@libs/SearchQueryUtils'; type SubstitutionMap = Record; -const getSubstitutionMapKey = (filterKey: SearchAutocompleteRangeKey, value: string) => `${filterKey}:${value}`; +const getSubstitutionMapKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; /** * Given a plaintext query and a SubstitutionMap object, this function will return a transformed query where: diff --git a/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts b/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts index d67cfce6b87cd..328eb3ff89814 100644 --- a/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts +++ b/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts @@ -1,8 +1,8 @@ -import type {SearchAutocompleteQueryRange, SearchAutocompleteRangeKey} from '@components/Search/types'; +import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; import {parse} from '@libs/SearchParser/autocompleteParser'; import type {SubstitutionMap} from './getQueryWithSubstitutions'; -const getSubstitutionsKey = (filterKey: SearchAutocompleteRangeKey, value: string) => `${filterKey}:${value}`; +const getSubstitutionsKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; /** * Given a plaintext query and a SubstitutionMap object, diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 204386a343a31..e859af64fe638 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -212,7 +212,8 @@ type SearchFilterKey = | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.TYPE | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.STATUS | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY - | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.COLUMNS; + | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.COLUMNS + | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT; type UserFriendlyKey = ValueOf; type UserFriendlyValue = ValueOf; From c6e2ffc2e4036e5506b59ca5e8d00743b9a97069 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 23 Jan 2026 08:16:10 +0300 Subject: [PATCH 06/13] chore: remove unnecessary comments --- src/components/Search/SearchAutocompleteList.tsx | 2 +- .../Search/SearchRouter/getQueryWithSubstitutions.ts | 4 ++-- .../Search/SearchRouter/getUpdatedSubstitutionsMap.ts | 4 ++-- src/components/Search/types.ts | 9 ++++++--- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 4ae6c8dccbe44..fbce8d445e0ad 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -332,7 +332,7 @@ function SearchAutocompleteList({ if (!autocomplete && ranges.length > 0) { const lastRange = ranges.at(ranges.length - 1); - if (lastRange && CONTINUATION_DETECTION_SEARCH_FILTER_KEYS.includes(lastRange.key)) { + if (lastRange && CONTINUATION_DETECTION_SEARCH_FILTER_KEYS.includes(lastRange.key as SearchFilterKey)) { const afterLastRange = autocompleteQueryValue.substring(lastRange.start + lastRange.length); const continuationMatch = afterLastRange.match(/^\s+(\w+)/); diff --git a/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts b/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts index 84895efb33a5b..794d26b108c56 100644 --- a/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts +++ b/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts @@ -1,10 +1,10 @@ -import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; +import type {SearchAutocompleteQueryRange, SearchAutocompleteRangeKey} from '@components/Search/types'; import {parse} from '@libs/SearchParser/autocompleteParser'; import {sanitizeSearchValue} from '@libs/SearchQueryUtils'; type SubstitutionMap = Record; -const getSubstitutionMapKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; +const getSubstitutionMapKey = (filterKey: SearchAutocompleteRangeKey, value: string) => `${filterKey}:${value}`; /** * Given a plaintext query and a SubstitutionMap object, this function will return a transformed query where: diff --git a/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts b/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts index 328eb3ff89814..d67cfce6b87cd 100644 --- a/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts +++ b/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts @@ -1,8 +1,8 @@ -import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; +import type {SearchAutocompleteQueryRange, SearchAutocompleteRangeKey} from '@components/Search/types'; import {parse} from '@libs/SearchParser/autocompleteParser'; import type {SubstitutionMap} from './getQueryWithSubstitutions'; -const getSubstitutionsKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; +const getSubstitutionsKey = (filterKey: SearchAutocompleteRangeKey, value: string) => `${filterKey}:${value}`; /** * Given a plaintext query and a SubstitutionMap object, diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index e859af64fe638..b7d8c95fbd23b 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -212,8 +212,10 @@ type SearchFilterKey = | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.TYPE | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.STATUS | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY - | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.COLUMNS - | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT; + | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.COLUMNS; + +// Extended type for autocomplete ranges - includes root keys that need highlighting but aren't form fields +type SearchAutocompleteRangeKey = SearchFilterKey | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT; type UserFriendlyKey = ValueOf; type UserFriendlyValue = ValueOf; @@ -263,7 +265,7 @@ type SearchAutocompleteResult = { }; type SearchAutocompleteQueryRange = { - key: SearchFilterKey; + key: SearchAutocompleteRangeKey; length: number; start: number; value: string; @@ -309,6 +311,7 @@ export type { RawFilterKey, RawQueryFilter, SearchFilterKey, + SearchAutocompleteRangeKey, UserFriendlyKey, ExpenseSearchStatus, InvoiceSearchStatus, From 3fecb6908abc6f1bbbcddb91e5ee15f3d6cba875 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 23 Jan 2026 09:27:00 +0300 Subject: [PATCH 07/13] test: Add test for comma-separated limit values --- tests/unit/Search/SearchQueryUtilsTest.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/unit/Search/SearchQueryUtilsTest.ts b/tests/unit/Search/SearchQueryUtilsTest.ts index e293a13807f9e..2d855c4aeb72a 100644 --- a/tests/unit/Search/SearchQueryUtilsTest.ts +++ b/tests/unit/Search/SearchQueryUtilsTest.ts @@ -738,6 +738,12 @@ describe('SearchQueryUtils', () => { expect(queryJSON?.limit).toBeUndefined(); }); + it('converts comma-separated limit to undefined', () => { + const queryJSON = buildSearchQueryJSON('type:expense limit:10,20'); + + expect(queryJSON?.limit).toBeUndefined(); + }); + it('uses last limit value when multiple limits specified', () => { const queryJSON = buildSearchQueryJSON('type:expense limit:10 limit:20'); From 8c7cfaef33108945604db1c632927040a7133ae4 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Fri, 23 Jan 2026 09:41:52 +0300 Subject: [PATCH 08/13] perf: Move getCurrentSearchQueryJSON inside useMemo callback --- src/pages/Search/AdvancedSearchFilters.tsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 95f0fc5c7845a..aaca69128ad0d 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -570,16 +570,14 @@ function AdvancedSearchFilters() { const {currentType, typeFiltersKeys} = useAdvancedSearchFilters(); - const currentQueryJSON = getCurrentSearchQueryJSON(); - const queryString = useMemo( - () => - buildQueryStringFromFilterFormValues(searchAdvancedFilters, { - sortBy: currentQueryJSON?.sortBy, - sortOrder: currentQueryJSON?.sortOrder, - limit: currentQueryJSON?.limit, - }), - [searchAdvancedFilters, currentQueryJSON?.sortBy, currentQueryJSON?.sortOrder, currentQueryJSON?.limit], - ); + const queryString = useMemo(() => { + const currentQueryJSON = getCurrentSearchQueryJSON(); + return buildQueryStringFromFilterFormValues(searchAdvancedFilters, { + sortBy: currentQueryJSON?.sortBy, + sortOrder: currentQueryJSON?.sortOrder, + limit: currentQueryJSON?.limit, + }); + }, [searchAdvancedFilters]); const queryJSON = useMemo(() => buildSearchQueryJSON(queryString || buildCannedSearchQuery()), [queryString]); const applyFiltersAndNavigate = () => { From fd3f422c1fa3c4465a93c0486e78e5a353ff84b8 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Mon, 26 Jan 2026 21:59:09 +0300 Subject: [PATCH 09/13] refactor: Move limit to end of query string to match SQL ordering --- src/libs/SearchQueryUtils.ts | 15 ++++++++------- tests/unit/Search/SearchQueryUtilsTest.ts | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 2d19f531c6ef4..88ed0ab2fc210 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -589,9 +589,6 @@ function buildQueryStringFromFilterFormValues(filterValues: Partial { const result = buildQueryStringFromFilterFormValues(filterValues, {limit: 10}); - expect(result).toEqual('sortBy:date sortOrder:desc limit:10 type:expense'); + expect(result).toEqual('sortBy:date sortOrder:desc type:expense limit:10'); }); test('combines limit with sort options', () => { @@ -288,7 +288,7 @@ describe('SearchQueryUtils', () => { const result = buildQueryStringFromFilterFormValues(filterValues, {sortBy: 'amount', sortOrder: 'asc', limit: 25}); - expect(result).toEqual('sortBy:amount sortOrder:asc limit:25 type:expense merchant:Amazon'); + expect(result).toEqual('sortBy:amount sortOrder:asc type:expense merchant:Amazon limit:25'); }); test('omits limit when not provided', () => { From a4b50b7019e4f831719821f34d44539137f9a485 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Mon, 26 Jan 2026 22:09:51 +0300 Subject: [PATCH 10/13] test: Assert empty/negated limit is treated as keyword --- tests/unit/Search/SearchQueryUtilsTest.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/Search/SearchQueryUtilsTest.ts b/tests/unit/Search/SearchQueryUtilsTest.ts index fc775257ec433..9156a32ddfede 100644 --- a/tests/unit/Search/SearchQueryUtilsTest.ts +++ b/tests/unit/Search/SearchQueryUtilsTest.ts @@ -754,12 +754,16 @@ describe('SearchQueryUtils', () => { const queryJSON = buildSearchQueryJSON('type:expense limit:'); expect(queryJSON?.limit).toBeUndefined(); + const keywordFilter = queryJSON?.flatFilters.find((filter) => filter.key === 'keyword'); + expect(keywordFilter?.filters.some((f) => f.value === 'limit:')).toBe(true); }); it('treats negated limit as keyword since limit is non-negatable', () => { const queryJSON = buildSearchQueryJSON('type:expense -limit:10'); expect(queryJSON?.limit).toBeUndefined(); + const keywordFilter = queryJSON?.flatFilters.find((filter) => filter.key === 'keyword'); + expect(keywordFilter?.filters.some((f) => f.value === '-limit:10')).toBe(true); }); }); From e77f2942a07c8f76634c3f1de95a488f19d4e113 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Tue, 27 Jan 2026 00:06:34 +0300 Subject: [PATCH 11/13] feat: Add limit filter to search with UI and parser support --- src/SCREENS.ts | 1 + src/components/Search/SearchAutocompleteList.tsx | 2 +- .../SearchRouter/getQueryWithSubstitutions.ts | 4 ++-- .../SearchRouter/getUpdatedSubstitutionsMap.ts | 4 ++-- src/components/Search/types.ts | 10 ++++------ src/hooks/useAdvancedSearchFilters.ts | 1 + src/languages/de.ts | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/languages/fr.ts | 1 + src/languages/it.ts | 1 + src/languages/ja.ts | 1 + src/languages/nl.ts | 1 + src/languages/pl.ts | 1 + src/languages/pt-BR.ts | 1 + src/languages/zh-hans.ts | 1 + .../AppNavigator/ModalStackNavigators/index.tsx | 1 + .../linkingConfig/RELATIONS/SEARCH_TO_RHP.ts | 1 + src/libs/Navigation/linkingConfig/config.ts | 1 + src/libs/SearchQueryUtils.ts | 11 ++++++++--- src/pages/Search/AdvancedSearchFilters.tsx | 5 +++++ .../SearchFiltersLimitPage.tsx | 15 +++++++++++++++ src/types/form/SearchAdvancedFiltersForm.ts | 3 +++ 23 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersLimitPage.tsx diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 617ab3c4d9a64..622309ed15e62 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -77,6 +77,7 @@ const SCREENS = { ADVANCED_FILTERS_WITHDRAWAL_ID_RHP: 'Search_Advanced_Filters_Withdrawal_ID_RHP', ADVANCED_FILTERS_TAG_RHP: 'Search_Advanced_Filters_Tag_RHP', ADVANCED_FILTERS_HAS_RHP: 'Search_Advanced_Filters_Has_RHP', + ADVANCED_FILTERS_LIMIT_RHP: 'Search_Advanced_Filters_Limit_RHP', ADVANCED_FILTERS_FROM_RHP: 'Search_Advanced_Filters_From_RHP', ADVANCED_FILTERS_TO_RHP: 'Search_Advanced_Filters_To_RHP', ADVANCED_FILTERS_TITLE_RHP: 'Search_Advanced_Filters_Title_RHP', diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index d82928228223b..a72735b5385b0 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -335,7 +335,7 @@ function SearchAutocompleteList({ if (!autocomplete && ranges.length > 0) { const lastRange = ranges.at(ranges.length - 1); - if (lastRange && CONTINUATION_DETECTION_SEARCH_FILTER_KEYS.includes(lastRange.key as SearchFilterKey)) { + if (lastRange && CONTINUATION_DETECTION_SEARCH_FILTER_KEYS.includes(lastRange.key)) { const afterLastRange = autocompleteQueryValue.substring(lastRange.start + lastRange.length); const continuationMatch = afterLastRange.match(/^\s+(\w+)/); diff --git a/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts b/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts index 794d26b108c56..84895efb33a5b 100644 --- a/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts +++ b/src/components/Search/SearchRouter/getQueryWithSubstitutions.ts @@ -1,10 +1,10 @@ -import type {SearchAutocompleteQueryRange, SearchAutocompleteRangeKey} from '@components/Search/types'; +import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; import {parse} from '@libs/SearchParser/autocompleteParser'; import {sanitizeSearchValue} from '@libs/SearchQueryUtils'; type SubstitutionMap = Record; -const getSubstitutionMapKey = (filterKey: SearchAutocompleteRangeKey, value: string) => `${filterKey}:${value}`; +const getSubstitutionMapKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; /** * Given a plaintext query and a SubstitutionMap object, this function will return a transformed query where: diff --git a/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts b/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts index d67cfce6b87cd..328eb3ff89814 100644 --- a/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts +++ b/src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts @@ -1,8 +1,8 @@ -import type {SearchAutocompleteQueryRange, SearchAutocompleteRangeKey} from '@components/Search/types'; +import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; import {parse} from '@libs/SearchParser/autocompleteParser'; import type {SubstitutionMap} from './getQueryWithSubstitutions'; -const getSubstitutionsKey = (filterKey: SearchAutocompleteRangeKey, value: string) => `${filterKey}:${value}`; +const getSubstitutionsKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; /** * Given a plaintext query and a SubstitutionMap object, diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 4bb7c8f1a60f9..5abffb7c6a3ff 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -193,6 +193,7 @@ type SearchTextFilterKeys = | typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD | typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.TITLE | typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWAL_ID + | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT | ReportFieldTextKey; type SearchDateFilterKeys = @@ -217,10 +218,8 @@ type SearchFilterKey = | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.TYPE | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.STATUS | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY - | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.COLUMNS; - -// Extended type for autocomplete ranges - includes root keys that need highlighting but aren't form fields -type SearchAutocompleteRangeKey = SearchFilterKey | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT; + | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.COLUMNS + | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT; type UserFriendlyKey = ValueOf; type UserFriendlyValue = ValueOf; @@ -270,7 +269,7 @@ type SearchAutocompleteResult = { }; type SearchAutocompleteQueryRange = { - key: SearchAutocompleteRangeKey; + key: SearchFilterKey; length: number; start: number; value: string; @@ -316,7 +315,6 @@ export type { RawFilterKey, RawQueryFilter, SearchFilterKey, - SearchAutocompleteRangeKey, UserFriendlyKey, ExpenseSearchStatus, InvoiceSearchStatus, diff --git a/src/hooks/useAdvancedSearchFilters.ts b/src/hooks/useAdvancedSearchFilters.ts index ac6c3a33c56aa..1072798855a21 100644 --- a/src/hooks/useAdvancedSearchFilters.ts +++ b/src/hooks/useAdvancedSearchFilters.ts @@ -30,6 +30,7 @@ const typeFiltersKeys = { CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY, CONST.SEARCH.SYNTAX_FILTER_KEYS.GROUP_CURRENCY, CONST.SEARCH.SYNTAX_FILTER_KEYS.HAS, + CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT, ], [ CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE, diff --git a/src/languages/de.ts b/src/languages/de.ts index c2fad2c1d6bcc..819f177ca9f79 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -6867,6 +6867,7 @@ Fordere Spesendetails wie Belege und Beschreibungen an, lege Limits und Standard status: 'Status', keyword: 'Schlüsselwort', keywords: 'Schlüsselwörter', + limit: 'Limit', currency: 'Währung', completed: 'Abgeschlossen', amount: { diff --git a/src/languages/en.ts b/src/languages/en.ts index c5633771ff1a5..34bf8d242b3c5 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6754,6 +6754,7 @@ const translations = { status: 'Status', keyword: 'Keyword', keywords: 'Keywords', + limit: 'Limit', currency: 'Currency', completed: 'Completed', amount: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 0838c71d6a795..fb56db2821bcc 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6504,6 +6504,7 @@ ${amount} para ${merchant} - ${date}`, status: 'Estado', keyword: 'Palabra clave', keywords: 'Palabras clave', + limit: 'Límite', currency: 'Divisa', completed: 'Completadas', card: { diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 6a5c7bb3fb6fe..6d90728a9caa4 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -6879,6 +6879,7 @@ Exigez des informations de dépense comme les reçus et les descriptions, défin status: 'Statut', keyword: 'Mot-clé', keywords: 'Mots-clés', + limit: 'Limite', currency: 'Devise', completed: 'Terminé', amount: { diff --git a/src/languages/it.ts b/src/languages/it.ts index 18d15db14ba39..338af3b1df883 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -6858,6 +6858,7 @@ Richiedi dettagli di spesa come ricevute e descrizioni, imposta limiti e valori status: 'Stato', keyword: 'Parola chiave', keywords: 'Parole chiave', + limit: 'Limite', currency: 'Valuta', completed: 'Completato', amount: { diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 03405dbb2bf8b..f4ed9c30a1cdf 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -6799,6 +6799,7 @@ ${reportName} status: 'ステータス', keyword: 'キーワード', keywords: 'キーワード', + limit: '制限', currency: '通貨', completed: '完了', amount: { diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 21ea94899f81b..338a0c0dc2df3 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -6839,6 +6839,7 @@ Vraag verplichte uitgavedetails zoals bonnetjes en beschrijvingen, stel limieten status: 'Status', keyword: 'Trefwoord', keywords: 'Trefwoorden', + limit: 'Limiet', currency: 'Valuta', completed: 'Voltooid', amount: { diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 9321009dd6a8c..a552c0c9ee75c 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -6829,6 +6829,7 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i status: 'Status', keyword: 'Słowo kluczowe', keywords: 'Słowa kluczowe', + limit: 'Limit', currency: 'Waluta', completed: 'Zakończone', amount: { diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index f9b0df02834ac..f012bd2677bda 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -6831,6 +6831,7 @@ Exija detalhes de despesas como recibos e descrições, defina limites e padrõe status: 'Status', keyword: 'Palavra-chave', keywords: 'Palavras-chave', + limit: 'Limite', currency: 'Moeda', completed: 'Concluído', amount: { diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 61517c31c4881..2a4c7b0027acd 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -6680,6 +6680,7 @@ ${reportName} status: '状态', keyword: '关键字', keywords: '关键词', + limit: '限制', currency: '货币', completed: '已完成', amount: { diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index f8a60900b6aff..4f67f5faed771 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -938,6 +938,7 @@ const SearchAdvancedFiltersModalStackNavigator = createModalStackNavigator require('../../../../pages/Search/SearchAdvancedFiltersPage/SearchFiltersIsPage').default, [SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP]: () => require('../../../../pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage').default, [SCREENS.SEARCH.ADVANCED_FILTERS_HAS_RHP]: () => require('../../../../pages/Search/SearchAdvancedFiltersPage/SearchFiltersHasPage').default, + [SCREENS.SEARCH.ADVANCED_FILTERS_LIMIT_RHP]: () => require('../../../../pages/Search/SearchAdvancedFiltersPage/SearchFiltersLimitPage').default, [SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP]: () => require('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersFromPage').default, [SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP]: () => require('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersToPage').default, [SCREENS.SEARCH.ADVANCED_FILTERS_IN_RHP]: () => require('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersInPage').default, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts index 9f36d76fd742d..aecf8e5770f68 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts @@ -36,6 +36,7 @@ const SEARCH_TO_RHP: Partial['config'] = { [SCREENS.SEARCH.ADVANCED_FILTERS_REIMBURSABLE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.REIMBURSABLE), [SCREENS.SEARCH.ADVANCED_FILTERS_WORKSPACE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.POLICY_ID), [SCREENS.SEARCH.ADVANCED_FILTERS_HAS_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.HAS), + [SCREENS.SEARCH.ADVANCED_FILTERS_LIMIT_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.LIMIT), [SCREENS.SEARCH.ADVANCED_FILTERS_PURCHASE_AMOUNT_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.PURCHASE_AMOUNT), [SCREENS.SEARCH.ADVANCED_FILTERS_PURCHASE_CURRENCY_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.PURCHASE_CURRENCY), [SCREENS.SEARCH.ADVANCED_FILTERS_ATTENDEE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.ATTENDEE), diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 88ed0ab2fc210..6c030db4568a6 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -584,7 +584,7 @@ function buildQueryStringFromFilterFormValues(filterValues: Partial + ); +} + +export default SearchFiltersLimitPage; diff --git a/src/types/form/SearchAdvancedFiltersForm.ts b/src/types/form/SearchAdvancedFiltersForm.ts index b87cc82af5633..09489573ea3dc 100644 --- a/src/types/form/SearchAdvancedFiltersForm.ts +++ b/src/types/form/SearchAdvancedFiltersForm.ts @@ -167,6 +167,7 @@ const FILTER_KEYS = { REPORT_FIELD: 'reportField', COLUMNS: 'columns', + LIMIT: 'limit', } as const; const ALLOWED_TYPE_FILTERS = { @@ -265,6 +266,7 @@ const ALLOWED_TYPE_FILTERS = { FILTER_KEYS.REPORT_FIELD, FILTER_KEYS.ATTENDEE_NOT, FILTER_KEYS.COLUMNS, + FILTER_KEYS.LIMIT, ], [CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT]: [ FILTER_KEYS.TYPE, @@ -674,6 +676,7 @@ type SearchAdvancedFiltersForm = Form< [FILTER_KEYS.IS]: string[]; [FILTER_KEYS.HAS]: string[]; [FILTER_KEYS.REPORT_FIELD]: string; + [FILTER_KEYS.LIMIT]: string; } & Record & Record & Record From e8f716069ba2b1948c36ee90eaa483279b932398 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Tue, 27 Jan 2026 00:14:18 +0300 Subject: [PATCH 12/13] refactor: Move limit check into switch statement --- src/libs/SearchAutocompleteUtils.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libs/SearchAutocompleteUtils.ts b/src/libs/SearchAutocompleteUtils.ts index 96f593e79aefb..547b56418d032 100644 --- a/src/libs/SearchAutocompleteUtils.ts +++ b/src/libs/SearchAutocompleteUtils.ts @@ -170,11 +170,6 @@ function filterOutRangesWithCorrectValue( return range.value.length > 0; } - if ((range.key as string) === CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT) { - const num = Number(range.value); - return Number.isInteger(num) && num > 0; - } - switch (range.key) { case CONST.SEARCH.SYNTAX_FILTER_KEYS.IN: case CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE: @@ -242,6 +237,10 @@ function filterOutRangesWithCorrectValue( return userFriendlyColumnList.has(range.value); case CONST.SEARCH.SYNTAX_FILTER_KEYS.IS: return isList.includes(range.value); + case CONST.SEARCH.SYNTAX_ROOT_KEYS.LIMIT: { + const num = Number(range.value); + return Number.isInteger(num) && num > 0; + } default: return false; } From e6719af8544160cb82767636db746c05b6207a52 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Tue, 27 Jan 2026 01:12:41 +0300 Subject: [PATCH 13/13] fix: Translate limit to maximumResults for backend API --- src/libs/actions/Search.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 10548f81f2eb8..4aac0949d66fa 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -410,13 +410,15 @@ function search({ } const {optimisticData, finallyData, failureData} = getOnyxLoadingData(queryJSON.hash, queryJSON, offset, isOffline, true); - const {flatFilters, ...queryJSONWithoutFlatFilters} = queryJSON; + const {flatFilters, limit, ...queryJSONWithoutFlatFilters} = queryJSON; const query = { ...queryJSONWithoutFlatFilters, searchKey, offset, filters: queryJSONWithoutFlatFilters.filters ?? null, shouldCalculateTotals, + // Backend expects 'maximumResults' instead of 'limit' + ...(limit !== undefined && {maximumResults: limit}), }; const jsonQuery = JSON.stringify(query); saveLastSearchParams({