From 030667b207eefbf4e78b1aae2609f5bf8a267467 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 12:44:24 -0600 Subject: [PATCH 01/14] update per-diem syntax --- src/CONST/index.ts | 8 + .../Search/SearchAutocompleteList.tsx | 3 +- src/components/Search/types.ts | 2 + src/libs/SearchAutocompleteUtils.ts | 3 +- src/libs/SearchParser/autocompleteParser.js | 282 +++++++++-------- src/libs/SearchParser/baseRules.peggy | 7 + src/libs/SearchParser/searchParser.js | 296 ++++++++++-------- src/libs/SearchParser/searchParser.peggy | 2 +- src/libs/SearchQueryUtils.ts | 23 +- 9 files changed, 365 insertions(+), 261 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index ea6ae8176303..698d412bd680 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6479,6 +6479,14 @@ const CONST = { BILLABLE: 'billable', ACTION: 'action', }, + get SEARCH_USER_FRIENDLY_VALUES_MAP() { + return { + [this.TRANSACTION_TYPE.PER_DIEM]: 'per-diem', + }; + }, + SEARCH_TEXT_TO_VALUE_MAP: { + 'per-diem': 'perDiem', + }, DATE_MODIFIERS: { ON: 'On', AFTER: 'After', diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index f8f1ddaa3e84..8d441c08eda7 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -31,7 +31,7 @@ import { getQueryWithoutAutocompletedPart, parseForAutocomplete, } from '@libs/SearchAutocompleteUtils'; -import {buildSearchQueryJSON, buildUserReadableQueryString, getQueryWithoutFilters, sanitizeSearchValue, shouldHighlight} from '@libs/SearchQueryUtils'; +import {buildSearchQueryJSON, buildUserReadableQueryString, getQueryWithoutFilters, getUserFriendlyValue, sanitizeSearchValue, shouldHighlight} from '@libs/SearchQueryUtils'; import {getDatePresets} from '@libs/SearchUIUtils'; import StringUtils from '@libs/StringUtils'; import Timing from '@userActions/Timing'; @@ -381,6 +381,7 @@ function SearchAutocompleteList( } case CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE: { const filteredExpenseTypes = expenseTypes + .map((value) => getUserFriendlyValue(value)) .filter((expenseType) => expenseType.includes(autocompleteValue.toLowerCase()) && !alreadyAutocompletedKeys.includes(expenseType)) .sort(); diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 368597087c6d..bda0093fa06f 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -131,6 +131,7 @@ type SearchFilterKey = | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY; type UserFriendlyKey = ValueOf; +type UserFriendlyValue = ValueOf; type QueryFilters = Array<{ key: SearchFilterKey; @@ -207,4 +208,5 @@ export type { SingularSearchStatus, SearchDatePreset, SearchWithdrawalType, + UserFriendlyValue, }; diff --git a/src/libs/SearchAutocompleteUtils.ts b/src/libs/SearchAutocompleteUtils.ts index a4064839e8d2..53dc8a9c1626 100644 --- a/src/libs/SearchAutocompleteUtils.ts +++ b/src/libs/SearchAutocompleteUtils.ts @@ -7,6 +7,7 @@ import CONST from '@src/CONST'; import type {PolicyCategories, PolicyTagLists, RecentlyUsedCategories, RecentlyUsedTags} from '@src/types/onyx'; import {getTagNamesFromTagsLists} from './PolicyUtils'; import {parse} from './SearchParser/autocompleteParser'; +import {getUserFriendlyValue} from './SearchQueryUtils'; /** * Parses given query using the autocomplete parser. @@ -123,7 +124,7 @@ function filterOutRangesWithCorrectValue( 'worklet'; const typeList = Object.values(CONST.SEARCH.DATA_TYPES) as string[]; - const expenseTypeList = Object.values(CONST.SEARCH.TRANSACTION_TYPE) as string[]; + const expenseTypeList = Object.values(CONST.SEARCH.TRANSACTION_TYPE).map((value) => getUserFriendlyValue(value)); const withdrawalTypeList = Object.values(CONST.SEARCH.WITHDRAWAL_TYPE) as string[]; const statusList = Object.values({ ...CONST.SEARCH.STATUS.EXPENSE, diff --git a/src/libs/SearchParser/autocompleteParser.js b/src/libs/SearchParser/autocompleteParser.js index 1943d351ae97..5bc4cbb46dfd 100644 --- a/src/libs/SearchParser/autocompleteParser.js +++ b/src/libs/SearchParser/autocompleteParser.js @@ -230,14 +230,16 @@ function peg$parse(input, options) { var peg$c44 = "createdby"; var peg$c45 = "created-by"; var peg$c46 = "action"; - var peg$c47 = "!="; - var peg$c48 = ">="; - var peg$c49 = ">"; - var peg$c50 = "<="; - var peg$c51 = "<"; - var peg$c52 = "\u201C"; - var peg$c53 = "\u201D"; - var peg$c54 = "\""; + var peg$c47 = "perdiem"; + var peg$c48 = "per-diem"; + var peg$c49 = "!="; + var peg$c50 = ">="; + var peg$c51 = ">"; + var peg$c52 = "<="; + var peg$c53 = "<"; + var peg$c54 = "\u201C"; + var peg$c55 = "\u201D"; + var peg$c56 = "\""; var peg$r0 = /^[:=]/; var peg$r1 = /^[^ ,\t\n\r\xA0]/; @@ -299,30 +301,32 @@ function peg$parse(input, options) { var peg$e45 = peg$literalExpectation("createdBy", true); var peg$e46 = peg$literalExpectation("created-by", true); var peg$e47 = peg$literalExpectation("action", true); - var peg$e48 = peg$otherExpectation("operator"); - var peg$e49 = peg$classExpectation([":", "="], false, false); - var peg$e50 = peg$literalExpectation("!=", false); - var peg$e51 = peg$literalExpectation(">=", false); - var peg$e52 = peg$literalExpectation(">", false); - var peg$e53 = peg$literalExpectation("<=", false); - var peg$e54 = peg$literalExpectation("<", false); - var peg$e55 = peg$otherExpectation("word"); - var peg$e56 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e57 = peg$otherExpectation("whitespace"); - var peg$e58 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); - var peg$e59 = peg$otherExpectation("quote"); - var peg$e60 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e61 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); - var peg$e62 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); - var peg$e63 = peg$literalExpectation("\u201C", false); - var peg$e64 = peg$literalExpectation("\u201D", false); - var peg$e65 = peg$literalExpectation("\"", false); - var peg$e66 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e67 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e68 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); - var peg$e69 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); - var peg$e70 = peg$anyExpectation(); - var peg$e71 = peg$classExpectation([","], false, false); + var peg$e48 = peg$literalExpectation("perDiem", true); + var peg$e49 = peg$literalExpectation("per-diem", true); + var peg$e50 = peg$otherExpectation("operator"); + var peg$e51 = peg$classExpectation([":", "="], false, false); + var peg$e52 = peg$literalExpectation("!=", false); + var peg$e53 = peg$literalExpectation(">=", false); + var peg$e54 = peg$literalExpectation(">", false); + var peg$e55 = peg$literalExpectation("<=", false); + var peg$e56 = peg$literalExpectation("<", false); + var peg$e57 = peg$otherExpectation("word"); + var peg$e58 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e59 = peg$otherExpectation("whitespace"); + var peg$e60 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); + var peg$e61 = peg$otherExpectation("quote"); + var peg$e62 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e63 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); + var peg$e64 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); + var peg$e65 = peg$literalExpectation("\u201C", false); + var peg$e66 = peg$literalExpectation("\u201D", false); + var peg$e67 = peg$literalExpectation("\"", false); + var peg$e68 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e69 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e70 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); + var peg$e71 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); + var peg$e72 = peg$anyExpectation(); + var peg$e73 = peg$classExpectation([","], false, false); var peg$f0 = function(ranges) { return { autocomplete, ranges }; }; var peg$f1 = function(filters) { return filters.filter(Boolean).flat(); }; @@ -414,28 +418,29 @@ function peg$parse(input, options) { var peg$f40 = function() { return "assignee"; }; var peg$f41 = function() { return "createdBy"; }; var peg$f42 = function() { return "action"; }; - var peg$f43 = function() { return "eq"; }; - var peg$f44 = function() { return "neq"; }; - var peg$f45 = function() { return "gte"; }; - var peg$f46 = function() { return "gt"; }; - var peg$f47 = function() { return "lte"; }; - var peg$f48 = function() { return "lt"; }; - var peg$f49 = function(o) { + var peg$f43 = function() { return "perDiem"; }; + var peg$f44 = function() { return "eq"; }; + var peg$f45 = function() { return "neq"; }; + var peg$f46 = function() { return "gte"; }; + var peg$f47 = function() { return "gt"; }; + var peg$f48 = function() { return "lte"; }; + var peg$f49 = function() { return "lt"; }; + var peg$f50 = function(o) { if (nameOperator) { expectingNestedQuote = (o === "eq"); // Use simple parser if no valid operator is found } return o; }; - var peg$f50 = function(chars) { return chars.join("").trim(); }; - var peg$f51 = function() { return "and"; }; - var peg$f52 = function() { return expectingNestedQuote; }; - var peg$f53 = function(start, inner, end) { //handle no-breaking space + var peg$f51 = function(chars) { return chars.join("").trim(); }; + var peg$f52 = function() { return "and"; }; + var peg$f53 = function() { return expectingNestedQuote; }; + var peg$f54 = function(start, inner, end) { //handle no-breaking space return [...start, '"', ...inner, '"', ...end].join(""); }; - var peg$f54 = function(start) {return "“"}; - var peg$f55 = function(start) {return "”"}; - var peg$f56 = function(start) {return "\""}; - var peg$f57 = function(start, inner, end) { + var peg$f55 = function(start) {return "“"}; + var peg$f56 = function(start) {return "”"}; + var peg$f57 = function(start) {return "\""}; + var peg$f58 = function(start, inner, end) { return [...start, '"', ...inner, '"'].join(""); }; var peg$currPos = options.peg$currPos | 0; @@ -1702,6 +1707,35 @@ function peg$parse(input, options) { return s0; } + function peg$parseperDiem() { + var s0, s1; + + s0 = input.substr(peg$currPos, 7); + if (s0.toLowerCase() === peg$c47) { + peg$currPos += 7; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e48); } + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = input.substr(peg$currPos, 8); + if (s1.toLowerCase() === peg$c48) { + peg$currPos += 8; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e49); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f43(); + } + s0 = s1; + } + + return s0; + } + function peg$parseoperator() { var s0, s1; @@ -1712,81 +1746,81 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e49); } + if (peg$silentFails === 0) { peg$fail(peg$e51); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f43(); + s1 = peg$f44(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c47) { - s1 = peg$c47; + if (input.substr(peg$currPos, 2) === peg$c49) { + s1 = peg$c49; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e50); } + if (peg$silentFails === 0) { peg$fail(peg$e52); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f44(); + s1 = peg$f45(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c48) { - s1 = peg$c48; + if (input.substr(peg$currPos, 2) === peg$c50) { + s1 = peg$c50; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e51); } + if (peg$silentFails === 0) { peg$fail(peg$e53); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f45(); + s1 = peg$f46(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c49; + s1 = peg$c51; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e52); } + if (peg$silentFails === 0) { peg$fail(peg$e54); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f46(); + s1 = peg$f47(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c50) { - s1 = peg$c50; + if (input.substr(peg$currPos, 2) === peg$c52) { + s1 = peg$c52; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e53); } + if (peg$silentFails === 0) { peg$fail(peg$e55); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f47(); + s1 = peg$f48(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c51; + s1 = peg$c53; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e54); } + if (peg$silentFails === 0) { peg$fail(peg$e56); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f48(); + s1 = peg$f49(); } s0 = s1; } @@ -1797,7 +1831,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e48); } + if (peg$silentFails === 0) { peg$fail(peg$e50); } } return s0; @@ -1810,7 +1844,7 @@ function peg$parse(input, options) { s1 = peg$parseoperator(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f49(s1); + s1 = peg$f50(s1); } s0 = s1; @@ -1828,7 +1862,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e56); } + if (peg$silentFails === 0) { peg$fail(peg$e58); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { @@ -1838,7 +1872,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e56); } + if (peg$silentFails === 0) { peg$fail(peg$e58); } } } } else { @@ -1846,13 +1880,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f50(s1); + s1 = peg$f51(s1); } s0 = s1; peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e55); } + if (peg$silentFails === 0) { peg$fail(peg$e57); } } return s0; @@ -1864,7 +1898,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$parse_(); peg$savedPos = s0; - s1 = peg$f51(); + s1 = peg$f52(); s0 = s1; return s0; @@ -1880,7 +1914,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e58); } + if (peg$silentFails === 0) { peg$fail(peg$e60); } } while (s1 !== peg$FAILED) { s0.push(s1); @@ -1889,12 +1923,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e58); } + if (peg$silentFails === 0) { peg$fail(peg$e60); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e57); } + if (peg$silentFails === 0) { peg$fail(peg$e59); } return s0; } @@ -1904,7 +1938,7 @@ function peg$parse(input, options) { s0 = peg$currPos; peg$savedPos = peg$currPos; - s1 = peg$f52(); + s1 = peg$f53(); if (s1) { s1 = undefined; } else { @@ -1941,7 +1975,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e60); } + if (peg$silentFails === 0) { peg$fail(peg$e62); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -1950,7 +1984,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e60); } + if (peg$silentFails === 0) { peg$fail(peg$e62); } } } s2 = input.charAt(peg$currPos); @@ -1958,7 +1992,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e61); } + if (peg$silentFails === 0) { peg$fail(peg$e63); } } if (s2 !== peg$FAILED) { s3 = []; @@ -1967,7 +2001,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -1976,7 +2010,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } } s4 = input.charAt(peg$currPos); @@ -1984,7 +2018,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e61); } + if (peg$silentFails === 0) { peg$fail(peg$e63); } } if (s4 !== peg$FAILED) { s5 = []; @@ -1993,7 +2027,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e56); } + if (peg$silentFails === 0) { peg$fail(peg$e58); } } while (s6 !== peg$FAILED) { s5.push(s6); @@ -2002,11 +2036,11 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e56); } + if (peg$silentFails === 0) { peg$fail(peg$e58); } } } peg$savedPos = s0; - s0 = peg$f53(s1, s3, s5); + s0 = peg$f54(s1, s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2018,7 +2052,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e59); } + if (peg$silentFails === 0) { peg$fail(peg$e61); } } return s0; @@ -2035,7 +2069,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e60); } + if (peg$silentFails === 0) { peg$fail(peg$e62); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2044,7 +2078,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e60); } + if (peg$silentFails === 0) { peg$fail(peg$e62); } } } s2 = input.charAt(peg$currPos); @@ -2052,7 +2086,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e61); } + if (peg$silentFails === 0) { peg$fail(peg$e63); } } if (s2 !== peg$FAILED) { s3 = []; @@ -2061,7 +2095,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -2077,15 +2111,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c52; + s6 = peg$c54; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e63); } + if (peg$silentFails === 0) { peg$fail(peg$e65); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f54(s1); + s4 = peg$f55(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2108,15 +2142,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c53; + s6 = peg$c55; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e64); } + if (peg$silentFails === 0) { peg$fail(peg$e66); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f55(s1); + s4 = peg$f56(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2139,15 +2173,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c54; + s6 = peg$c56; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e65); } + if (peg$silentFails === 0) { peg$fail(peg$e67); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f56(s1); + s4 = peg$f57(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2166,7 +2200,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -2182,15 +2216,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c52; + s6 = peg$c54; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e63); } + if (peg$silentFails === 0) { peg$fail(peg$e65); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f54(s1); + s4 = peg$f55(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2213,15 +2247,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c53; + s6 = peg$c55; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e64); } + if (peg$silentFails === 0) { peg$fail(peg$e66); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f55(s1); + s4 = peg$f56(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2244,15 +2278,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c54; + s6 = peg$c56; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e65); } + if (peg$silentFails === 0) { peg$fail(peg$e67); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f56(s1); + s4 = peg$f57(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2268,7 +2302,7 @@ function peg$parse(input, options) { s4 = peg$parseclosingQuote(); if (s4 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f57(s1, s3, s4); + s0 = peg$f58(s1, s3, s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2280,7 +2314,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e59); } + if (peg$silentFails === 0) { peg$fail(peg$e61); } } return s0; @@ -2295,7 +2329,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e61); } + if (peg$silentFails === 0) { peg$fail(peg$e63); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2333,7 +2367,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e66); } + if (peg$silentFails === 0) { peg$fail(peg$e68); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2342,7 +2376,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e66); } + if (peg$silentFails === 0) { peg$fail(peg$e68); } } } s2 = []; @@ -2351,7 +2385,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e67); } + if (peg$silentFails === 0) { peg$fail(peg$e69); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -2360,7 +2394,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e67); } + if (peg$silentFails === 0) { peg$fail(peg$e69); } } } s3 = []; @@ -2369,7 +2403,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e68); } + if (peg$silentFails === 0) { peg$fail(peg$e70); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -2378,7 +2412,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e68); } + if (peg$silentFails === 0) { peg$fail(peg$e70); } } } s4 = peg$parseoperator(); @@ -2397,7 +2431,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e69); } + if (peg$silentFails === 0) { peg$fail(peg$e71); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2406,7 +2440,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e69); } + if (peg$silentFails === 0) { peg$fail(peg$e71); } } } s2 = peg$currPos; @@ -2427,7 +2461,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e70); } + if (peg$silentFails === 0) { peg$fail(peg$e72); } } peg$silentFails--; if (s4 === peg$FAILED) { @@ -2453,7 +2487,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e71); } + if (peg$silentFails === 0) { peg$fail(peg$e73); } } } } diff --git a/src/libs/SearchParser/baseRules.peggy b/src/libs/SearchParser/baseRules.peggy index 31d7e573796d..eaca32705565 100644 --- a/src/libs/SearchParser/baseRules.peggy +++ b/src/libs/SearchParser/baseRules.peggy @@ -67,6 +67,13 @@ assignee = "assignee"i { return "assignee"; } createdBy = "createdBy"i / "created-by"i { return "createdBy"; } action = "action"i { return "action"; } +// Value transformation rules +values + = perDiem + +perDiem + = "perDiem"i / "per-diem"i { return "perDiem"; } + operator "operator" = (":" / "=") { return "eq"; } / "!=" { return "neq"; } diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index 7be15ccd7a34..4a4283f9a33f 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -231,14 +231,16 @@ function peg$parse(input, options) { var peg$c44 = "createdby"; var peg$c45 = "created-by"; var peg$c46 = "action"; - var peg$c47 = "!="; - var peg$c48 = ">="; - var peg$c49 = ">"; - var peg$c50 = "<="; - var peg$c51 = "<"; - var peg$c52 = "\u201C"; - var peg$c53 = "\u201D"; - var peg$c54 = "\""; + var peg$c47 = "perdiem"; + var peg$c48 = "per-diem"; + var peg$c49 = "!="; + var peg$c50 = ">="; + var peg$c51 = ">"; + var peg$c52 = "<="; + var peg$c53 = "<"; + var peg$c54 = "\u201C"; + var peg$c55 = "\u201D"; + var peg$c56 = "\""; var peg$r0 = /^[^ \t\r\n\xA0]/; var peg$r1 = /^[:=]/; @@ -303,30 +305,32 @@ function peg$parse(input, options) { var peg$e47 = peg$literalExpectation("createdBy", true); var peg$e48 = peg$literalExpectation("created-by", true); var peg$e49 = peg$literalExpectation("action", true); - var peg$e50 = peg$otherExpectation("operator"); - var peg$e51 = peg$classExpectation([":", "="], false, false); - var peg$e52 = peg$literalExpectation("!=", false); - var peg$e53 = peg$literalExpectation(">=", false); - var peg$e54 = peg$literalExpectation(">", false); - var peg$e55 = peg$literalExpectation("<=", false); - var peg$e56 = peg$literalExpectation("<", false); - var peg$e57 = peg$otherExpectation("word"); - var peg$e58 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e59 = peg$otherExpectation("whitespace"); - var peg$e60 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); - var peg$e61 = peg$otherExpectation("quote"); - var peg$e62 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e63 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); - var peg$e64 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); - var peg$e65 = peg$literalExpectation("\u201C", false); - var peg$e66 = peg$literalExpectation("\u201D", false); - var peg$e67 = peg$literalExpectation("\"", false); - var peg$e68 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e69 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e70 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); - var peg$e71 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); - var peg$e72 = peg$anyExpectation(); - var peg$e73 = peg$classExpectation([","], false, false); + var peg$e50 = peg$literalExpectation("perDiem", true); + var peg$e51 = peg$literalExpectation("per-diem", true); + var peg$e52 = peg$otherExpectation("operator"); + var peg$e53 = peg$classExpectation([":", "="], false, false); + var peg$e54 = peg$literalExpectation("!=", false); + var peg$e55 = peg$literalExpectation(">=", false); + var peg$e56 = peg$literalExpectation(">", false); + var peg$e57 = peg$literalExpectation("<=", false); + var peg$e58 = peg$literalExpectation("<", false); + var peg$e59 = peg$otherExpectation("word"); + var peg$e60 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e61 = peg$otherExpectation("whitespace"); + var peg$e62 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); + var peg$e63 = peg$otherExpectation("quote"); + var peg$e64 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e65 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); + var peg$e66 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); + var peg$e67 = peg$literalExpectation("\u201C", false); + var peg$e68 = peg$literalExpectation("\u201D", false); + var peg$e69 = peg$literalExpectation("\"", false); + var peg$e70 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e71 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e72 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); + var peg$e73 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); + var peg$e74 = peg$anyExpectation(); + var peg$e75 = peg$classExpectation([","], false, false); var peg$f0 = function(filters) { return applyDefaults(filters); }; var peg$f1 = function(head, tail) { @@ -430,28 +434,29 @@ function peg$parse(input, options) { var peg$f41 = function() { return "assignee"; }; var peg$f42 = function() { return "createdBy"; }; var peg$f43 = function() { return "action"; }; - var peg$f44 = function() { return "eq"; }; - var peg$f45 = function() { return "neq"; }; - var peg$f46 = function() { return "gte"; }; - var peg$f47 = function() { return "gt"; }; - var peg$f48 = function() { return "lte"; }; - var peg$f49 = function() { return "lt"; }; - var peg$f50 = function(o) { + var peg$f44 = function() { return "perDiem"; }; + var peg$f45 = function() { return "eq"; }; + var peg$f46 = function() { return "neq"; }; + var peg$f47 = function() { return "gte"; }; + var peg$f48 = function() { return "gt"; }; + var peg$f49 = function() { return "lte"; }; + var peg$f50 = function() { return "lt"; }; + var peg$f51 = function(o) { if (nameOperator) { expectingNestedQuote = (o === "eq"); // Use simple parser if no valid operator is found } return o; }; - var peg$f51 = function(chars) { return chars.join("").trim(); }; - var peg$f52 = function() { return "and"; }; - var peg$f53 = function() { return expectingNestedQuote; }; - var peg$f54 = function(start, inner, end) { //handle no-breaking space + var peg$f52 = function(chars) { return chars.join("").trim(); }; + var peg$f53 = function() { return "and"; }; + var peg$f54 = function() { return expectingNestedQuote; }; + var peg$f55 = function(start, inner, end) { //handle no-breaking space return [...start, '"', ...inner, '"', ...end].join(""); }; - var peg$f55 = function(start) {return "“"}; - var peg$f56 = function(start) {return "”"}; - var peg$f57 = function(start) {return "\""}; - var peg$f58 = function(start, inner, end) { + var peg$f56 = function(start) {return "“"}; + var peg$f57 = function(start) {return "”"}; + var peg$f58 = function(start) {return "\""}; + var peg$f59 = function(start, inner, end) { return [...start, '"', ...inner, '"'].join(""); }; var peg$currPos = options.peg$currPos | 0; @@ -989,9 +994,12 @@ function peg$parse(input, options) { } s2 = peg$currPos; s3 = []; - s4 = peg$parsequotedString(); + s4 = peg$parseperDiem(); if (s4 === peg$FAILED) { - s4 = peg$parsealphanumeric(); + s4 = peg$parsequotedString(); + if (s4 === peg$FAILED) { + s4 = peg$parsealphanumeric(); + } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -1019,9 +1027,12 @@ function peg$parse(input, options) { s5 = peg$FAILED; } if (s5 !== peg$FAILED) { - s5 = peg$parsequotedString(); + s5 = peg$parseperDiem(); if (s5 === peg$FAILED) { - s5 = peg$parsealphanumeric(); + s5 = peg$parsequotedString(); + if (s5 === peg$FAILED) { + s5 = peg$parsealphanumeric(); + } } if (s5 === peg$FAILED) { peg$currPos = s4; @@ -1896,6 +1907,35 @@ function peg$parse(input, options) { return s0; } + function peg$parseperDiem() { + var s0, s1; + + s0 = input.substr(peg$currPos, 7); + if (s0.toLowerCase() === peg$c47) { + peg$currPos += 7; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e50); } + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = input.substr(peg$currPos, 8); + if (s1.toLowerCase() === peg$c48) { + peg$currPos += 8; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e51); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f44(); + } + s0 = s1; + } + + return s0; + } + function peg$parseoperator() { var s0, s1; @@ -1906,81 +1946,81 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e51); } + if (peg$silentFails === 0) { peg$fail(peg$e53); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f44(); + s1 = peg$f45(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c47) { - s1 = peg$c47; + if (input.substr(peg$currPos, 2) === peg$c49) { + s1 = peg$c49; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e52); } + if (peg$silentFails === 0) { peg$fail(peg$e54); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f45(); + s1 = peg$f46(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c48) { - s1 = peg$c48; + if (input.substr(peg$currPos, 2) === peg$c50) { + s1 = peg$c50; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e53); } + if (peg$silentFails === 0) { peg$fail(peg$e55); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f46(); + s1 = peg$f47(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c49; + s1 = peg$c51; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e54); } + if (peg$silentFails === 0) { peg$fail(peg$e56); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f47(); + s1 = peg$f48(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c50) { - s1 = peg$c50; + if (input.substr(peg$currPos, 2) === peg$c52) { + s1 = peg$c52; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e55); } + if (peg$silentFails === 0) { peg$fail(peg$e57); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f48(); + s1 = peg$f49(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c51; + s1 = peg$c53; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e56); } + if (peg$silentFails === 0) { peg$fail(peg$e58); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f49(); + s1 = peg$f50(); } s0 = s1; } @@ -1991,7 +2031,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e50); } + if (peg$silentFails === 0) { peg$fail(peg$e52); } } return s0; @@ -2004,7 +2044,7 @@ function peg$parse(input, options) { s1 = peg$parseoperator(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f50(s1); + s1 = peg$f51(s1); } s0 = s1; @@ -2022,7 +2062,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e58); } + if (peg$silentFails === 0) { peg$fail(peg$e60); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { @@ -2032,7 +2072,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e58); } + if (peg$silentFails === 0) { peg$fail(peg$e60); } } } } else { @@ -2040,13 +2080,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f51(s1); + s1 = peg$f52(s1); } s0 = s1; peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e57); } + if (peg$silentFails === 0) { peg$fail(peg$e59); } } return s0; @@ -2058,7 +2098,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$parse_(); peg$savedPos = s0; - s1 = peg$f52(); + s1 = peg$f53(); s0 = s1; return s0; @@ -2074,7 +2114,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e60); } + if (peg$silentFails === 0) { peg$fail(peg$e62); } } while (s1 !== peg$FAILED) { s0.push(s1); @@ -2083,12 +2123,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e60); } + if (peg$silentFails === 0) { peg$fail(peg$e62); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e59); } + if (peg$silentFails === 0) { peg$fail(peg$e61); } return s0; } @@ -2098,7 +2138,7 @@ function peg$parse(input, options) { s0 = peg$currPos; peg$savedPos = peg$currPos; - s1 = peg$f53(); + s1 = peg$f54(); if (s1) { s1 = undefined; } else { @@ -2135,7 +2175,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2144,7 +2184,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } } s2 = input.charAt(peg$currPos); @@ -2152,7 +2192,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e63); } + if (peg$silentFails === 0) { peg$fail(peg$e65); } } if (s2 !== peg$FAILED) { s3 = []; @@ -2161,7 +2201,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e64); } + if (peg$silentFails === 0) { peg$fail(peg$e66); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -2170,7 +2210,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e64); } + if (peg$silentFails === 0) { peg$fail(peg$e66); } } } s4 = input.charAt(peg$currPos); @@ -2178,7 +2218,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e63); } + if (peg$silentFails === 0) { peg$fail(peg$e65); } } if (s4 !== peg$FAILED) { s5 = []; @@ -2187,7 +2227,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e58); } + if (peg$silentFails === 0) { peg$fail(peg$e60); } } while (s6 !== peg$FAILED) { s5.push(s6); @@ -2196,11 +2236,11 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e58); } + if (peg$silentFails === 0) { peg$fail(peg$e60); } } } peg$savedPos = s0; - s0 = peg$f54(s1, s3, s5); + s0 = peg$f55(s1, s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2212,7 +2252,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e61); } + if (peg$silentFails === 0) { peg$fail(peg$e63); } } return s0; @@ -2229,7 +2269,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2238,7 +2278,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e62); } + if (peg$silentFails === 0) { peg$fail(peg$e64); } } } s2 = input.charAt(peg$currPos); @@ -2246,7 +2286,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e63); } + if (peg$silentFails === 0) { peg$fail(peg$e65); } } if (s2 !== peg$FAILED) { s3 = []; @@ -2255,7 +2295,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e64); } + if (peg$silentFails === 0) { peg$fail(peg$e66); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -2271,15 +2311,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c52; + s6 = peg$c54; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e65); } + if (peg$silentFails === 0) { peg$fail(peg$e67); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f55(s1); + s4 = peg$f56(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2302,15 +2342,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c53; + s6 = peg$c55; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e66); } + if (peg$silentFails === 0) { peg$fail(peg$e68); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f56(s1); + s4 = peg$f57(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2333,15 +2373,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c54; + s6 = peg$c56; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e67); } + if (peg$silentFails === 0) { peg$fail(peg$e69); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f57(s1); + s4 = peg$f58(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2360,7 +2400,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e64); } + if (peg$silentFails === 0) { peg$fail(peg$e66); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -2376,15 +2416,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c52; + s6 = peg$c54; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e65); } + if (peg$silentFails === 0) { peg$fail(peg$e67); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f55(s1); + s4 = peg$f56(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2407,15 +2447,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c53; + s6 = peg$c55; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e66); } + if (peg$silentFails === 0) { peg$fail(peg$e68); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f56(s1); + s4 = peg$f57(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2438,15 +2478,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c54; + s6 = peg$c56; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e67); } + if (peg$silentFails === 0) { peg$fail(peg$e69); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f57(s1); + s4 = peg$f58(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2462,7 +2502,7 @@ function peg$parse(input, options) { s4 = peg$parseclosingQuote(); if (s4 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f58(s1, s3, s4); + s0 = peg$f59(s1, s3, s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2474,7 +2514,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e61); } + if (peg$silentFails === 0) { peg$fail(peg$e63); } } return s0; @@ -2489,7 +2529,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e63); } + if (peg$silentFails === 0) { peg$fail(peg$e65); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2527,7 +2567,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e68); } + if (peg$silentFails === 0) { peg$fail(peg$e70); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2536,7 +2576,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e68); } + if (peg$silentFails === 0) { peg$fail(peg$e70); } } } s2 = []; @@ -2545,7 +2585,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e69); } + if (peg$silentFails === 0) { peg$fail(peg$e71); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -2554,7 +2594,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e69); } + if (peg$silentFails === 0) { peg$fail(peg$e71); } } } s3 = []; @@ -2563,7 +2603,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e70); } + if (peg$silentFails === 0) { peg$fail(peg$e72); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -2572,7 +2612,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e70); } + if (peg$silentFails === 0) { peg$fail(peg$e72); } } } s4 = peg$parseoperator(); @@ -2591,7 +2631,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e71); } + if (peg$silentFails === 0) { peg$fail(peg$e73); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2600,7 +2640,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e71); } + if (peg$silentFails === 0) { peg$fail(peg$e73); } } } s2 = peg$currPos; @@ -2621,7 +2661,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e72); } + if (peg$silentFails === 0) { peg$fail(peg$e74); } } peg$silentFails--; if (s4 === peg$FAILED) { @@ -2647,7 +2687,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e73); } + if (peg$silentFails === 0) { peg$fail(peg$e75); } } } } diff --git a/src/libs/SearchParser/searchParser.peggy b/src/libs/SearchParser/searchParser.peggy index 12bb400a06d6..74ea36adad25 100644 --- a/src/libs/SearchParser/searchParser.peggy +++ b/src/libs/SearchParser/searchParser.peggy @@ -151,7 +151,7 @@ filterKey defaultKey "default key" = @(type / status / sortBy / sortOrder / policyID / groupBy) identifier - = (","+)? parts:(quotedString / alphanumeric)|1.., ","+| empty:(","+)? { + = (","+)? parts:(values / quotedString / alphanumeric)|1.., ","+| empty:(","+)? { const value = parts.flat().filter(Boolean).map((word) => { if (word.startsWith('"') && word.endsWith('"') && word.length >= 2) { return word.slice(1, -1); diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 312aa37f1e58..238f1d1a264b 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -14,6 +14,7 @@ import type { SearchStatus, SearchWithdrawalType, UserFriendlyKey, + UserFriendlyValue, } from '@components/Search/types'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -167,11 +168,11 @@ function buildFilterValuesString(filterName: string, queryFilters: QueryFilter[] index !== 0 && ((queryFilter.operator === 'eq' && queryFilters?.at(index - 1)?.operator === 'eq') || (queryFilter.operator === 'neq' && queryFilters.at(index - 1)?.operator === 'neq')) ) { - filterValueString += `${delimiter}${sanitizeSearchValue(queryFilter.value.toString())}`; + filterValueString += `${delimiter}${sanitizeSearchValue(getUserFriendlyValue(queryFilter.value.toString()))}`; } else if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD) { - filterValueString += `${delimiter}${sanitizeSearchValue(queryFilter.value.toString())}`; + filterValueString += `${delimiter}${sanitizeSearchValue(getUserFriendlyValue(queryFilter.value.toString()))}`; } else { - filterValueString += ` ${filterName}${operatorToCharMap[queryFilter.operator]}${sanitizeSearchValue(queryFilter.value.toString())}`; + filterValueString += ` ${filterName}${operatorToCharMap[queryFilter.operator]}${sanitizeSearchValue(getUserFriendlyValue(queryFilter.value.toString()))}`; } }); @@ -208,13 +209,13 @@ function getFilters(queryJSON: SearchQueryJSON) { if (!Array.isArray(node.right)) { filterArray.push({ operator: node.operator, - value: node.right as string | number, + value: CONST.SEARCH.SEARCH_TEXT_TO_VALUE_MAP[node.right as keyof typeof CONST.SEARCH.SEARCH_TEXT_TO_VALUE_MAP] ?? node.right as string | number, }); } else { node.right.forEach((element) => { filterArray.push({ operator: node.operator, - value: element, + value: CONST.SEARCH.SEARCH_TEXT_TO_VALUE_MAP[element as keyof typeof CONST.SEARCH.SEARCH_TEXT_TO_VALUE_MAP] ?? element, }); }); } @@ -1051,6 +1052,16 @@ function getUserFriendlyKey(keyName: SearchFilterKey | typeof CONST.SEARCH.SYNTA return UserFriendlyKeyMap[keyName]; } +/** + * Converts a filter value from backend value to display text value + * + * @example + * getUserFriendlyValues("perDiem") // returns "per-diem" + */ +function getUserFriendlyValue(value: string): UserFriendlyValue { + return CONST.SEARCH.SEARCH_USER_FRIENDLY_VALUES_MAP[value as keyof typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_VALUES_MAP] ?? value; +} + function shouldHighlight(referenceText: string, searchText: string) { if (!referenceText || !searchText) { return false; @@ -1080,10 +1091,10 @@ export { getQueryWithUpdatedValues, getCurrentSearchQueryJSON, getQueryWithoutFilters, - getUserFriendlyKey, isDefaultExpensesQuery, sortOptionsWithEmptyValue, shouldHighlight, getAllPolicyValues, getTodoSearchQuery, + getUserFriendlyValue, }; From fba6548e2f6ff827288c1ced9d3bb9ac9009f9d3 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 13:32:50 -0600 Subject: [PATCH 02/14] update user friendly map --- src/libs/SearchQueryUtils.ts | 74 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 238f1d1a264b..310d31b0c457 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -60,44 +60,44 @@ const operatorToCharMap = { * A mapping object that maps filter names from the internal codebase format to user-friendly names. */ const UserFriendlyKeyMap: Record = { - type: 'type', - status: 'status', - sortBy: 'sort-by', - sortOrder: 'sort-order', - policyID: 'workspace', - date: 'date', - amount: 'amount', - expenseType: 'expense-type', - currency: 'currency', - merchant: 'merchant', - description: 'description', - from: 'from', - to: 'to', - payer: 'payer', - exporter: 'exporter', - category: 'category', - tag: 'tag', - taxRate: 'tax-rate', - cardID: 'card', - feed: 'feed', - // cspell:disable-next-line - reportID: 'reportid', - keyword: 'keyword', - in: 'in', - submitted: 'submitted', - approved: 'approved', - paid: 'paid', - exported: 'exported', - posted: 'posted', - withdrawalType: 'withdrawal-type', - withdrawn: 'withdrawn', - groupBy: 'group-by', - title: 'title', - assignee: 'assignee', - billable: 'billable', - reimbursable: 'reimbursable', - action: 'action', + [CONST.SEARCH.SYNTAX_FILTER_KEYS.TYPE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TYPE, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.STATUS]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.STATUS, + [CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.SORT_BY, + [CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.SORT_ORDER, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.POLICY_ID, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.DATE, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.AMOUNT, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.EXPENSE_TYPE, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.CURRENCY, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.MERCHANT, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.DESCRIPTION]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.DESCRIPTION, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.FROM, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.TO]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TO, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.PAYER]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.PAYER, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTER]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.EXPORTER, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.CATEGORY, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TAG, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TAX_RATE, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.CARD_ID, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.FEED, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_ID]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.REPORT_ID, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.KEYWORD, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.IN]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.IN, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.SUBMITTED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.SUBMITTED, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.APPROVED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.APPROVED, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.PAID]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.PAID, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.EXPORTED, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.POSTED, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWAL_TYPE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.WITHDRAWAL_TYPE, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWN]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.WITHDRAWN, + [CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.GROUP_BY, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.TITLE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TITLE, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.ASSIGNEE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.ASSIGNEE, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.BILLABLE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.BILLABLE, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.REIMBURSABLE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.REIMBURSABLE, + [CONST.SEARCH.SYNTAX_FILTER_KEYS.ACTION]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.ACTION, }; + /** * @private * Returns string value wrapped in quotes "", if the value contains space or   (no-breaking space). From c23418496e5cec8b5b3220b315699c7de068b70c Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 13:38:08 -0600 Subject: [PATCH 03/14] refactor static map --- src/libs/SearchQueryUtils.ts | 62 +++++++++++++----------------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 310d31b0c457..ff23fea90124 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -57,46 +57,28 @@ const operatorToCharMap = { }; /** - * A mapping object that maps filter names from the internal codebase format to user-friendly names. + * Dynamically maps filter names from the internal codebase format to user-friendly names. + * This function automatically finds the corresponding user-friendly key for any filter key. */ -const UserFriendlyKeyMap: Record = { - [CONST.SEARCH.SYNTAX_FILTER_KEYS.TYPE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TYPE, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.STATUS]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.STATUS, - [CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.SORT_BY, - [CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.SORT_ORDER, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.POLICY_ID, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.DATE, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.AMOUNT, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.EXPENSE_TYPE, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.CURRENCY, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.MERCHANT, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.DESCRIPTION]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.DESCRIPTION, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.FROM, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.TO]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TO, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.PAYER]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.PAYER, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTER]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.EXPORTER, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.CATEGORY, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TAG, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TAX_RATE, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.CARD_ID, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.FEED, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_ID]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.REPORT_ID, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.KEYWORD, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.IN]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.IN, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.SUBMITTED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.SUBMITTED, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.APPROVED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.APPROVED, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.PAID]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.PAID, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.EXPORTED, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.POSTED, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWAL_TYPE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.WITHDRAWAL_TYPE, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWN]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.WITHDRAWN, - [CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.GROUP_BY, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.TITLE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TITLE, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.ASSIGNEE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.ASSIGNEE, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.BILLABLE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.BILLABLE, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.REIMBURSABLE]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.REIMBURSABLE, - [CONST.SEARCH.SYNTAX_FILTER_KEYS.ACTION]: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.ACTION, -}; +function getUserFriendlyKeyFromMap(keyName: SearchFilterKey | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER): UserFriendlyKey { + // Find the corresponding key name in the SYNTAX objects + const filterKeyName = Object.keys(CONST.SEARCH.SYNTAX_FILTER_KEYS).find( + (key) => CONST.SEARCH.SYNTAX_FILTER_KEYS[key as keyof typeof CONST.SEARCH.SYNTAX_FILTER_KEYS] === keyName + ); + + const rootKeyName = Object.keys(CONST.SEARCH.SYNTAX_ROOT_KEYS).find( + (key) => CONST.SEARCH.SYNTAX_ROOT_KEYS[key as keyof typeof CONST.SEARCH.SYNTAX_ROOT_KEYS] === keyName + ); + + const foundKeyName = filterKeyName ?? rootKeyName; + + if (foundKeyName && foundKeyName in CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS) { + return CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS[foundKeyName as keyof typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS]; + } + + // Fallback to the original key if no mapping is found + return keyName as UserFriendlyKey; +} /** * @private @@ -1049,7 +1031,7 @@ function getQueryWithoutFilters(searchQuery: string) { * 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 { - return UserFriendlyKeyMap[keyName]; + return getUserFriendlyKeyFromMap(keyName); } /** From b8c16aeefd24a2cbe9c4c379f993145a5ee698f8 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 14:19:39 -0600 Subject: [PATCH 04/14] use dynamic maps --- src/CONST/index.ts | 3 - src/libs/SearchQueryUtils.ts | 109 ++++++++++++++++++++--------------- 2 files changed, 64 insertions(+), 48 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 698d412bd680..e0dfabe83d87 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6484,9 +6484,6 @@ const CONST = { [this.TRANSACTION_TYPE.PER_DIEM]: 'per-diem', }; }, - SEARCH_TEXT_TO_VALUE_MAP: { - 'per-diem': 'perDiem', - }, DATE_MODIFIERS: { ON: 'On', AFTER: 'After', diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index ff23fea90124..c08f6850be7e 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -56,28 +56,72 @@ const operatorToCharMap = { [CONST.SEARCH.SYNTAX_OPERATORS.OR]: ' ' as const, }; -/** - * Dynamically maps filter names from the internal codebase format to user-friendly names. - * This function automatically finds the corresponding user-friendly key for any filter key. - */ -function getUserFriendlyKeyFromMap(keyName: SearchFilterKey | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER): UserFriendlyKey { - // Find the corresponding key name in the SYNTAX objects - const filterKeyName = Object.keys(CONST.SEARCH.SYNTAX_FILTER_KEYS).find( - (key) => CONST.SEARCH.SYNTAX_FILTER_KEYS[key as keyof typeof CONST.SEARCH.SYNTAX_FILTER_KEYS] === keyName - ); +// Create reverse lookup maps for O(1) performance +const createKeyToUserFriendlyMap = () => { + const map = new Map(); - const rootKeyName = Object.keys(CONST.SEARCH.SYNTAX_ROOT_KEYS).find( - (key) => CONST.SEARCH.SYNTAX_ROOT_KEYS[key as keyof typeof CONST.SEARCH.SYNTAX_ROOT_KEYS] === keyName - ); + // Map SYNTAX_FILTER_KEYS values to their user-friendly names + Object.entries(CONST.SEARCH.SYNTAX_FILTER_KEYS).forEach(([keyName, keyValue]) => { + if (!(keyName in CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS)) { + return; + } + map.set(keyValue, CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS[keyName as keyof typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS]); + }); + + // Map SYNTAX_ROOT_KEYS values to their user-friendly names + Object.entries(CONST.SEARCH.SYNTAX_ROOT_KEYS).forEach(([keyName, keyValue]) => { + if (!(keyName in CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS)) { + return; + } + map.set(keyValue, CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS[keyName as keyof typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS]); + }); - const foundKeyName = filterKeyName ?? rootKeyName; + return map; +}; + +const createDisplayTextToValueMap = () => { + const map = new Map(); - if (foundKeyName && foundKeyName in CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS) { - return CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS[foundKeyName as keyof typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS]; - } + // Create reverse mapping from user-friendly values to backend keys + Object.entries(CONST.SEARCH.SEARCH_USER_FRIENDLY_VALUES_MAP).forEach(([backendKey, userFriendlyValue]) => { + map.set(userFriendlyValue, backendKey); + }); - // Fallback to the original key if no mapping is found - return keyName as UserFriendlyKey; + return map; +}; + +// Create the maps once at module initialization for performance +const keyToUserFriendlyMap = createKeyToUserFriendlyMap(); +const displayTextToValueMap = createDisplayTextToValueMap(); + +/** + * Lookup a key in the keyToUserFriendlyMap and return the user-friendly key. + * + * @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 { + return (keyToUserFriendlyMap.get(keyName) ?? keyName) as UserFriendlyKey; +} + +/** + * Lookup a value in the displayTextToValueMap and return the backend value. + * + * @example + * getUserFriendlyValueFromMap("per-diem") // returns "perDiem" + */ +function getUserFriendlyValueFromMap(searchText: string): string { + return displayTextToValueMap.get(searchText) ?? searchText; +} + +/** + * Converts a filter value from backend value to user friendly display text. + * + * @example + * getUserFriendlyValues("perDiem") // returns "per-diem" + */ +function getUserFriendlyValue(value: string): UserFriendlyValue { + return CONST.SEARCH.SEARCH_USER_FRIENDLY_VALUES_MAP[value as keyof typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_VALUES_MAP] ?? value; } /** @@ -191,13 +235,13 @@ function getFilters(queryJSON: SearchQueryJSON) { if (!Array.isArray(node.right)) { filterArray.push({ operator: node.operator, - value: CONST.SEARCH.SEARCH_TEXT_TO_VALUE_MAP[node.right as keyof typeof CONST.SEARCH.SEARCH_TEXT_TO_VALUE_MAP] ?? node.right as string | number, + value: getUserFriendlyValueFromMap(String(node.right)) as string | number, }); } else { node.right.forEach((element) => { filterArray.push({ operator: node.operator, - value: CONST.SEARCH.SEARCH_TEXT_TO_VALUE_MAP[element as keyof typeof CONST.SEARCH.SEARCH_TEXT_TO_VALUE_MAP] ?? element, + value: getUserFriendlyValueFromMap(String(element)), }); }); } @@ -1019,31 +1063,6 @@ function getQueryWithoutFilters(searchQuery: string) { return keywordFilter?.filters.map((filter) => filter.value).join(' ') ?? ''; } -/** - * Converts a filter key from old naming (camelCase) to user friendly naming (kebab-case). - * - * There are two types of keys used in the context of Search. - * The `camelCase` naming (ex: `sortBy`, `taxRate`) is more friendly to developers, but not nice to show to people. This was the default key naming in the past. - * The "user friendly" naming (ex: `sort-by`, `tax-rate`) was introduced at a later point, to offer better experience for the users. - * Currently search parsers support both versions as an input, but output the `camelCase` form. Whenever we display some query to the user however, we always do it in the newer pretty format. - * - * @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 { - return getUserFriendlyKeyFromMap(keyName); -} - -/** - * Converts a filter value from backend value to display text value - * - * @example - * getUserFriendlyValues("perDiem") // returns "per-diem" - */ -function getUserFriendlyValue(value: string): UserFriendlyValue { - return CONST.SEARCH.SEARCH_USER_FRIENDLY_VALUES_MAP[value as keyof typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_VALUES_MAP] ?? value; -} - function shouldHighlight(referenceText: string, searchText: string) { if (!referenceText || !searchText) { return false; From b196b8461c68cac00f6de830df46845b41fc5f13 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 14:21:20 -0600 Subject: [PATCH 05/14] add comment --- src/CONST/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index e0dfabe83d87..8df74c350143 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6479,6 +6479,8 @@ const CONST = { BILLABLE: 'billable', ACTION: 'action', }, + + // Maps an internal search value to the user friendly display text, e.g. `perDiem` -> `per-diem` get SEARCH_USER_FRIENDLY_VALUES_MAP() { return { [this.TRANSACTION_TYPE.PER_DIEM]: 'per-diem', From a75edecdfed4731d7a80bb539ac5a1c7ec837abd Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 14:25:20 -0600 Subject: [PATCH 06/14] fix prettier --- src/libs/SearchQueryUtils.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index c08f6850be7e..c355907f7629 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -59,7 +59,7 @@ const operatorToCharMap = { // Create reverse lookup maps for O(1) performance const createKeyToUserFriendlyMap = () => { const map = new Map(); - + // Map SYNTAX_FILTER_KEYS values to their user-friendly names Object.entries(CONST.SEARCH.SYNTAX_FILTER_KEYS).forEach(([keyName, keyValue]) => { if (!(keyName in CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS)) { @@ -67,7 +67,7 @@ const createKeyToUserFriendlyMap = () => { } map.set(keyValue, CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS[keyName as keyof typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS]); }); - + // Map SYNTAX_ROOT_KEYS values to their user-friendly names Object.entries(CONST.SEARCH.SYNTAX_ROOT_KEYS).forEach(([keyName, keyValue]) => { if (!(keyName in CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS)) { @@ -75,18 +75,18 @@ const createKeyToUserFriendlyMap = () => { } map.set(keyValue, CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS[keyName as keyof typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS]); }); - + return map; }; const createDisplayTextToValueMap = () => { const map = new Map(); - + // Create reverse mapping from user-friendly values to backend keys Object.entries(CONST.SEARCH.SEARCH_USER_FRIENDLY_VALUES_MAP).forEach(([backendKey, userFriendlyValue]) => { map.set(userFriendlyValue, backendKey); }); - + return map; }; @@ -96,7 +96,7 @@ const displayTextToValueMap = createDisplayTextToValueMap(); /** * Lookup a key in the keyToUserFriendlyMap and return the user-friendly key. - * + * * @example * getUserFriendlyKey("taxRate") // returns "tax-rate" */ @@ -106,7 +106,7 @@ function getUserFriendlyKey(keyName: SearchFilterKey | typeof CONST.SEARCH.SYNTA /** * Lookup a value in the displayTextToValueMap and return the backend value. - * + * * @example * getUserFriendlyValueFromMap("per-diem") // returns "perDiem" */ From 7b7fb064f790655a79c7cb005454aad96e5800c0 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 14:42:13 -0600 Subject: [PATCH 07/14] add tests --- tests/unit/SearchAutocompleteParserTest.ts | 12 ++++++++++++ tests/unit/SearchParserTest.ts | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/tests/unit/SearchAutocompleteParserTest.ts b/tests/unit/SearchAutocompleteParserTest.ts index 207ed20a4125..e43388d6d7f2 100644 --- a/tests/unit/SearchAutocompleteParserTest.ts +++ b/tests/unit/SearchAutocompleteParserTest.ts @@ -247,6 +247,18 @@ const tests = [ ], }, }, + { + query: 'expense-type:per-diem', + expected: { + autocomplete: { + key: 'expenseType', + value: 'per-diem', + start: 13, + length: 8, + }, + ranges: [{key: 'expenseType', value: 'per-diem', start: 13, length: 8}], + }, + }, ]; const nameFieldContinuationTests = [ diff --git a/tests/unit/SearchParserTest.ts b/tests/unit/SearchParserTest.ts index 89e531308f40..6e1f41696b77 100644 --- a/tests/unit/SearchParserTest.ts +++ b/tests/unit/SearchParserTest.ts @@ -616,6 +616,20 @@ const keywordTests = [ }, }, }, + { + query: 'expense-type:per-diem', + expected: { + type: 'expense', + status: CONST.SEARCH.STATUS.EXPENSE.ALL, + sortBy: 'date', + sortOrder: 'desc', + filters: { + operator: 'eq', + left: 'expenseType', + right: 'perDiem', + }, + }, + }, ]; describe('search parser', () => { From a560af9ec6e8ec7324a867d42a9ea7f7c9eab6f5 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 15:47:37 -0600 Subject: [PATCH 08/14] dont convert keyword values --- src/libs/SearchQueryUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index c355907f7629..a79599380b86 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -196,7 +196,7 @@ function buildFilterValuesString(filterName: string, queryFilters: QueryFilter[] ) { filterValueString += `${delimiter}${sanitizeSearchValue(getUserFriendlyValue(queryFilter.value.toString()))}`; } else if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD) { - filterValueString += `${delimiter}${sanitizeSearchValue(getUserFriendlyValue(queryFilter.value.toString()))}`; + filterValueString += `${delimiter}${sanitizeSearchValue(queryFilter.value.toString())}`; } else { filterValueString += ` ${filterName}${operatorToCharMap[queryFilter.operator]}${sanitizeSearchValue(getUserFriendlyValue(queryFilter.value.toString()))}`; } From 5f124994502d52db88655210ebe956ab5845305b Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 16:39:27 -0600 Subject: [PATCH 09/14] only update readable string --- src/libs/SearchQueryUtils.ts | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index a79599380b86..53aad6ea5475 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -79,20 +79,8 @@ const createKeyToUserFriendlyMap = () => { return map; }; -const createDisplayTextToValueMap = () => { - const map = new Map(); - - // Create reverse mapping from user-friendly values to backend keys - Object.entries(CONST.SEARCH.SEARCH_USER_FRIENDLY_VALUES_MAP).forEach(([backendKey, userFriendlyValue]) => { - map.set(userFriendlyValue, backendKey); - }); - - return map; -}; - // Create the maps once at module initialization for performance const keyToUserFriendlyMap = createKeyToUserFriendlyMap(); -const displayTextToValueMap = createDisplayTextToValueMap(); /** * Lookup a key in the keyToUserFriendlyMap and return the user-friendly key. @@ -104,16 +92,6 @@ function getUserFriendlyKey(keyName: SearchFilterKey | typeof CONST.SEARCH.SYNTA return (keyToUserFriendlyMap.get(keyName) ?? keyName) as UserFriendlyKey; } -/** - * Lookup a value in the displayTextToValueMap and return the backend value. - * - * @example - * getUserFriendlyValueFromMap("per-diem") // returns "perDiem" - */ -function getUserFriendlyValueFromMap(searchText: string): string { - return displayTextToValueMap.get(searchText) ?? searchText; -} - /** * Converts a filter value from backend value to user friendly display text. * @@ -194,11 +172,11 @@ function buildFilterValuesString(filterName: string, queryFilters: QueryFilter[] index !== 0 && ((queryFilter.operator === 'eq' && queryFilters?.at(index - 1)?.operator === 'eq') || (queryFilter.operator === 'neq' && queryFilters.at(index - 1)?.operator === 'neq')) ) { - filterValueString += `${delimiter}${sanitizeSearchValue(getUserFriendlyValue(queryFilter.value.toString()))}`; + filterValueString += `${delimiter}${sanitizeSearchValue(queryFilter.value.toString())}`; } else if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD) { filterValueString += `${delimiter}${sanitizeSearchValue(queryFilter.value.toString())}`; } else { - filterValueString += ` ${filterName}${operatorToCharMap[queryFilter.operator]}${sanitizeSearchValue(getUserFriendlyValue(queryFilter.value.toString()))}`; + filterValueString += ` ${filterName}${operatorToCharMap[queryFilter.operator]}${sanitizeSearchValue(queryFilter.value.toString())}`; } }); @@ -235,13 +213,13 @@ function getFilters(queryJSON: SearchQueryJSON) { if (!Array.isArray(node.right)) { filterArray.push({ operator: node.operator, - value: getUserFriendlyValueFromMap(String(node.right)) as string | number, + value: String(node.right) as string | number, }); } else { node.right.forEach((element) => { filterArray.push({ operator: node.operator, - value: getUserFriendlyValueFromMap(String(element)), + value: String(element), }); }); } @@ -866,7 +844,7 @@ function buildUserReadableQueryString( } else { displayQueryFilters = queryFilter.map((filter) => ({ operator: filter.operator, - value: getFilterDisplayValue(key, filter.value.toString(), PersonalDetails, reports, cardList, cardFeeds, policies), + value: getFilterDisplayValue(key, getUserFriendlyValue(filter.value.toString()), PersonalDetails, reports, cardList, cardFeeds, policies), })); } title += buildFilterValuesString(getUserFriendlyKey(key), displayQueryFilters); From a9ab1b3154503333151e7dfb5ab84935e57fec91 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 13 Aug 2025 16:42:05 -0600 Subject: [PATCH 10/14] style --- src/libs/SearchQueryUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 53aad6ea5475..815faf811d5c 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -213,13 +213,13 @@ function getFilters(queryJSON: SearchQueryJSON) { if (!Array.isArray(node.right)) { filterArray.push({ operator: node.operator, - value: String(node.right) as string | number, + value: node.right as string | number, }); } else { node.right.forEach((element) => { filterArray.push({ operator: node.operator, - value: String(element), + value: element, }); }); } From 0f8461724a679c407693b359b0cc649c77384daa Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 15 Aug 2025 09:57:21 -0600 Subject: [PATCH 11/14] move list map --- src/libs/SearchAutocompleteUtils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/SearchAutocompleteUtils.ts b/src/libs/SearchAutocompleteUtils.ts index 53dc8a9c1626..ab5ce140619d 100644 --- a/src/libs/SearchAutocompleteUtils.ts +++ b/src/libs/SearchAutocompleteUtils.ts @@ -110,6 +110,8 @@ function getAutocompleteQueryWithComma(prevQuery: string, newQuery: string) { return newQuery; } +const userFriendlyExpenseTypeList = Object.values(CONST.SEARCH.TRANSACTION_TYPE).map((value) => getUserFriendlyValue(value)); + /** * @private */ @@ -124,7 +126,7 @@ function filterOutRangesWithCorrectValue( 'worklet'; const typeList = Object.values(CONST.SEARCH.DATA_TYPES) as string[]; - const expenseTypeList = Object.values(CONST.SEARCH.TRANSACTION_TYPE).map((value) => getUserFriendlyValue(value)); + const expenseTypeList = userFriendlyExpenseTypeList; const withdrawalTypeList = Object.values(CONST.SEARCH.WITHDRAWAL_TYPE) as string[]; const statusList = Object.values({ ...CONST.SEARCH.STATUS.EXPENSE, From 3c5cc10b587256320bb39a49e0333b7884d0358b Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 15 Aug 2025 13:26:53 -0600 Subject: [PATCH 12/14] export function --- src/libs/SearchQueryUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 434e9ce9471f..83dc81293caa 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -1087,4 +1087,5 @@ export { getAllPolicyValues, getTodoSearchQuery, getUserFriendlyValue, + getUserFriendlyKey, }; From eb85c6d07c25469e612354b456047a2862da81a7 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 15 Aug 2025 13:33:15 -0600 Subject: [PATCH 13/14] prettier --- Mobile-Expensify | 2 +- src/components/Search/SearchAutocompleteList.tsx | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index 2e6c756412a7..e23e10508a84 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit 2e6c756412a7064c4fcbd7d2cf71125ab2b4b3bf +Subproject commit e23e10508a84e362c621aa683a87ca821658a6a1 diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 80cd97118cce..5cfc3d215740 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -31,7 +31,15 @@ import { getQueryWithoutAutocompletedPart, parseForAutocomplete, } from '@libs/SearchAutocompleteUtils'; -import {buildSearchQueryJSON, buildUserReadableQueryString, getQueryWithoutFilters, getUserFriendlyKey, getUserFriendlyValue, sanitizeSearchValue, shouldHighlight} from '@libs/SearchQueryUtils'; +import { + buildSearchQueryJSON, + buildUserReadableQueryString, + getQueryWithoutFilters, + getUserFriendlyKey, + getUserFriendlyValue, + sanitizeSearchValue, + shouldHighlight, +} from '@libs/SearchQueryUtils'; import {getDatePresets} from '@libs/SearchUIUtils'; import StringUtils from '@libs/StringUtils'; import Timing from '@userActions/Timing'; From c55886374888bcb10f6878e573568e9b2ffc782f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 19 Aug 2025 10:35:07 -0600 Subject: [PATCH 14/14] fix lint --- src/components/MoneyRequestConfirmationListFooter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index 8c4839b61289..3e86553612fb 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -15,7 +15,7 @@ import DistanceRequestUtils from '@libs/DistanceRequestUtils'; import {isMovingTransactionFromTrackExpense} from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import {getDestinationForDisplay, getSubratesFields, getSubratesForDisplay, getTimeDifferenceIntervals, getTimeForDisplay} from '@libs/PerDiemRequestUtils'; -import {canSendInvoice, getPerDiemCustomUnit, isPaidGroupPolicy} from '@libs/PolicyUtils'; +import {canSendInvoice, getPerDiemCustomUnit} from '@libs/PolicyUtils'; import type {ThumbnailAndImageURI} from '@libs/ReceiptUtils'; import {getThumbnailAndImageURIs} from '@libs/ReceiptUtils'; import {