From 684d4966cb99d891b98e513fae8671194f074920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Miko=C5=82ajczak?= Date: Tue, 13 Feb 2024 23:02:57 +0100 Subject: [PATCH] replace localeCompare with primitive comparison --- src/libs/GroupChatUtils.ts | 3 ++- src/libs/KeyboardShortcut/index.ts | 3 ++- src/libs/ReportUtils.ts | 5 +++-- src/libs/SidebarUtils.ts | 11 ++++++----- src/libs/stringCompare/index.native.ts | 18 ++++++++++++++++++ src/libs/stringCompare/index.ts | 11 +++++++++++ 6 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 src/libs/stringCompare/index.native.ts create mode 100644 src/libs/stringCompare/index.ts diff --git a/src/libs/GroupChatUtils.ts b/src/libs/GroupChatUtils.ts index 26b3665ca4ce..37a18430917e 100644 --- a/src/libs/GroupChatUtils.ts +++ b/src/libs/GroupChatUtils.ts @@ -1,5 +1,6 @@ import type {Report} from '@src/types/onyx'; import * as ReportUtils from './ReportUtils'; +import stringCompare from './stringCompare'; /** * Returns the report name if the report is a group chat @@ -10,7 +11,7 @@ function getGroupChatName(report: Report): string | undefined { return participants .map((participant) => ReportUtils.getDisplayNameForParticipant(participant, isMultipleParticipantReport)) - .sort((first, second) => first?.localeCompare(second ?? '') ?? 0) + .sort((first, second) => stringCompare(first ?? '', second ?? '') ?? 0) .filter(Boolean) .join(', '); } diff --git a/src/libs/KeyboardShortcut/index.ts b/src/libs/KeyboardShortcut/index.ts index 44ba54953c40..63fc5fb2bcff 100644 --- a/src/libs/KeyboardShortcut/index.ts +++ b/src/libs/KeyboardShortcut/index.ts @@ -1,6 +1,7 @@ import Str from 'expensify-common/lib/str'; import * as KeyCommand from 'react-native-key-command'; import getOperatingSystem from '@libs/getOperatingSystem'; +import stringCompare from '@libs/stringCompare'; import CONST from '@src/CONST'; import bindHandlerToKeydownEvent from './bindHandlerToKeydownEvent'; @@ -32,7 +33,7 @@ type Shortcut = { const documentedShortcuts: Record = {}; function getDocumentedShortcuts(): Shortcut[] { - return Object.values(documentedShortcuts).sort((a, b) => a.displayName.localeCompare(b.displayName)); + return Object.values(documentedShortcuts).sort((a, b) => stringCompare(a.displayName, b.displayName)); } const keyInputEnter = KeyCommand?.constants?.keyInputEnter?.toString() ?? 'keyInputEnter'; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 181ce5461dd7..a679c5ff7a1d 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -38,6 +38,7 @@ import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import * as PolicyUtils from './PolicyUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; +import stringCompare from './stringCompare'; import * as TransactionUtils from './TransactionUtils'; import * as Url from './Url'; import * as UserUtils from './UserUtils'; @@ -1296,7 +1297,7 @@ function getIconsForParticipants(participants: number[], personalDetails: OnyxCo const sortedParticipantDetails = participantDetails.sort((first, second) => { // First sort by displayName/login - const displayNameLoginOrder = first[1].localeCompare(second[1]); + const displayNameLoginOrder = stringCompare(first[1], second[1]); if (displayNameLoginOrder !== 0) { return displayNameLoginOrder; } @@ -1545,7 +1546,7 @@ function getDisplayNamesWithTooltips( }) .sort((first, second) => { // First sort by displayName/login - const displayNameLoginOrder = first.displayName.localeCompare(second.displayName); + const displayNameLoginOrder = stringCompare(first.displayName, second.displayName); if (displayNameLoginOrder !== 0) { return displayNameLoginOrder; } diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 6e46ec320066..fbe0fee1ff33 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -19,6 +19,7 @@ import * as OptionsListUtils from './OptionsListUtils'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; import * as ReportUtils from './ReportUtils'; +import stringCompare from './stringCompare'; import * as TaskUtils from './TaskUtils'; import * as UserUtils from './UserUtils'; @@ -200,20 +201,20 @@ function getOrderedReportIDs( }); // Sort each group of reports accordingly - pinnedAndGBRReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0)); - draftReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0)); + pinnedAndGBRReports.sort((a, b) => (a?.displayName && b?.displayName ? stringCompare(a.displayName, b.displayName) : 0)); + draftReports.sort((a, b) => (a?.displayName && b?.displayName ? stringCompare(a.displayName, b.displayName) : 0)); if (isInDefaultMode) { nonArchivedReports.sort((a, b) => { const compareDates = a?.lastVisibleActionCreated && b?.lastVisibleActionCreated ? compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) : 0; - const compareDisplayNames = a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0; + const compareDisplayNames = a?.displayName && b?.displayName ? stringCompare(a.displayName, b.displayName) : 0; return compareDates || compareDisplayNames; }); // For archived reports ensure that most recent reports are at the top by reversing the order archivedReports.sort((a, b) => (a?.lastVisibleActionCreated && b?.lastVisibleActionCreated ? compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) : 0)); } else { - nonArchivedReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0)); - archivedReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0)); + nonArchivedReports.sort((a, b) => (a?.displayName && b?.displayName ? stringCompare(a.displayName, b.displayName) : 0)); + archivedReports.sort((a, b) => (a?.displayName && b?.displayName ? stringCompare(a.displayName, b.displayName) : 0)); } // Now that we have all the reports grouped and sorted, they must be flattened into an array and only return the reportID. diff --git a/src/libs/stringCompare/index.native.ts b/src/libs/stringCompare/index.native.ts new file mode 100644 index 000000000000..311334025be4 --- /dev/null +++ b/src/libs/stringCompare/index.native.ts @@ -0,0 +1,18 @@ +/** + * Compare two strings in a case-insensitive manner. It is a performance fallback for the built-in String.localeCompare method in Hermes. + * @param a - The first string to compare + * @param b - The second string to compare + * @returns - `1` if first string takes precedence, `-1` if second string takes precedence, `0` if they are equal + */ +function stringCompare(a: string, b: string): number { + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; +} + +// eslint-disable-next-line import/prefer-default-export +export default stringCompare; diff --git a/src/libs/stringCompare/index.ts b/src/libs/stringCompare/index.ts new file mode 100644 index 000000000000..1aa4605cc0da --- /dev/null +++ b/src/libs/stringCompare/index.ts @@ -0,0 +1,11 @@ +/** + * Compare two strings in a case-insensitive manner. It is a performance fallback for Hermes engine. For other engines, it is a wrapper around the built-in localeCompare method. + * @param a - The first string to compare + * @param b - The second string to compare + * @returns - `1` if first string takes precedence, `-1` if second string takes precedence, `0` if they are equal + */ +function stringCompare(a: string, b: string): number { + return a.localeCompare(b); +} + +export default stringCompare;