Skip to content

Commit

Permalink
fix: tag search causing regex exception (#938)
Browse files Browse the repository at this point in the history
  • Loading branch information
amanharwara authored Mar 19, 2022
1 parent 105c0cd commit 8265d94
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 29 deletions.
11 changes: 6 additions & 5 deletions app/assets/javascripts/components/AutocompleteTagResult.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AppState } from '@/ui_models/app_state';
import { splitQueryInString } from '@/utils/stringUtils';
import { SNTag } from '@standardnotes/snjs';
import { observer } from 'mobx-react-lite';
import { useEffect, useRef } from 'preact/hooks';
Expand Down Expand Up @@ -71,7 +72,7 @@ export const AutocompleteTagResult = observer(

useEffect(() => {
if (focusedTagResultUuid === tagResult.uuid) {
tagResultRef.current!.focus();
tagResultRef.current?.focus();
appState.noteTags.setFocusedTagResultUuid(undefined);
}
}, [appState.noteTags, focusedTagResultUuid, tagResult]);
Expand All @@ -92,9 +93,8 @@ export const AutocompleteTagResult = observer(
{prefixTitle && <span className="grey-2">{prefixTitle}</span>}
{autocompleteSearchQuery === ''
? title
: title
.split(new RegExp(`(${autocompleteSearchQuery})`, 'gi'))
.map((substring, index) => (
: splitQueryInString(title, autocompleteSearchQuery).map(
(substring, index) => (
<span
key={index}
className={`${
Expand All @@ -106,7 +106,8 @@ export const AutocompleteTagResult = observer(
>
{substring}
</span>
))}
)
)}
</span>
</button>
);
Expand Down
65 changes: 65 additions & 0 deletions app/assets/javascripts/utils/stringUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {
getIndexOfQueryInString,
splitQueryInString,
splitRangeWithinString,
} from './stringUtils';

describe('string utils', () => {
describe('splitRangeWithinString', () => {
it('should return whole string if range is invalid or out of bounds', () => {
const string = 'test-string';

const outOfBoundsStartResult = splitRangeWithinString(string, 15, 0);
expect(outOfBoundsStartResult).toStrictEqual(['test-string']);

const outOfBoundsEndResult = splitRangeWithinString(string, 0, -15);
expect(outOfBoundsEndResult).toStrictEqual(['test-string']);

const invalidRangeResult = splitRangeWithinString(string, 15, 0);
expect(invalidRangeResult).toStrictEqual(['test-string']);
});

it('should return split string if range is valid', () => {
const string = 'test-string';

const case1 = splitRangeWithinString(string, 0, 3);
expect(case1).toStrictEqual(['tes', 't-string']);

const case2 = splitRangeWithinString(string, 2, 6);
expect(case2).toStrictEqual(['te', 'st-s', 'tring']);

const case3 = splitRangeWithinString(string, 4, 9);
expect(case3).toStrictEqual(['test', '-stri', 'ng']);
});
});

describe('getIndexOfQueryInString', () => {
it('should get correct index of query in string', () => {
const string = 'tEsT-sTrInG';

const indexOfQuery1 = getIndexOfQueryInString(string, 'tRi');
expect(indexOfQuery1).toBe(6);

const indexOfQuery2 = getIndexOfQueryInString(string, 'StR');
expect(indexOfQuery2).toBe(5);

const indexOfQuery3 = getIndexOfQueryInString(string, 'stringUtils');
expect(indexOfQuery3).toBe(-1);
});
});

describe('splitQueryInString', () => {
it('should split string if it includes the query', () => {
const string = 'TeSt-StRiNg';

const query1Result = splitQueryInString(string, 'T-sTr');
expect(query1Result).toStrictEqual(['TeS', 't-StR', 'iNg']);

const query2Result = splitQueryInString(string, 'InG');
expect(query2Result).toStrictEqual(['TeSt-StR', 'iNg']);

const query3Result = splitQueryInString(string, 'invalid query');
expect(query3Result).toStrictEqual(['TeSt-StRiNg']);
});
});
});
39 changes: 39 additions & 0 deletions app/assets/javascripts/utils/stringUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export const splitRangeWithinString = (
string: string,
start: number,
end: number
) => {
const isStartOutOfBounds = start > string.length || start < 0;
const isEndOutOfBounds = end > string.length || end < 0;
const isInvalidRange = start > end;

if (isStartOutOfBounds || isEndOutOfBounds || isInvalidRange) {
return [string];
} else {
return [
string.slice(0, start),
string.slice(start, end),
string.slice(end),
].filter((slice) => slice.length > 0);
}
};

export const getIndexOfQueryInString = (string: string, query: string) => {
const lowercasedTitle = string.toLowerCase();
const lowercasedQuery = query.toLowerCase();
return lowercasedTitle.indexOf(lowercasedQuery);
};

export const splitQueryInString = (string: string, query: string) => {
const indexOfQueryInTitle = getIndexOfQueryInString(string, query);

if (indexOfQueryInTitle < 0) {
return [string];
}

return splitRangeWithinString(
string,
indexOfQueryInTitle,
indexOfQueryInTitle + query.length
);
};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@
"@reach/listbox": "^0.16.2",
"@reach/tooltip": "^0.16.2",
"@standardnotes/components": "1.7.12",
"@standardnotes/features": "1.35.0",
"@standardnotes/features": "1.35.1",
"@standardnotes/filepicker": "1.10.0",
"@standardnotes/settings": "1.13.1",
"@standardnotes/sncrypto-web": "1.8.0",
"@standardnotes/snjs": "2.86.2",
"@standardnotes/snjs": "2.86.4",
"@zip.js/zip.js": "^2.4.7",
"mobx": "^6.5.0",
"mobx-react-lite": "^3.3.0",
Expand Down
111 changes: 89 additions & 22 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2345,6 +2345,13 @@
dependencies:
"@standardnotes/common" "^1.16.0"

"@standardnotes/applications@^1.2.3":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@standardnotes/applications/-/applications-1.2.3.tgz#03f9067c20fb2960560bc084e9e37981044ee373"
integrity sha512-YiQZzjiApTGSOUosidks99O3I1AQv5gzJ12+yc99GKYno564nn0QHOUMKqIgMJsEG+Yp6gJ2QpgzC/0hmUUlVQ==
dependencies:
"@standardnotes/common" "^1.16.1"

"@standardnotes/auth@^3.17.7":
version "3.17.7"
resolved "https://registry.yarnpkg.com/@standardnotes/auth/-/auth-3.17.7.tgz#cb53b415c9a5a61a8721d7099d0d13d8ab79b597"
Expand All @@ -2353,25 +2360,46 @@
"@standardnotes/common" "^1.16.0"
jsonwebtoken "^8.5.1"

"@standardnotes/auth@^3.17.8":
version "3.17.8"
resolved "https://registry.yarnpkg.com/@standardnotes/auth/-/auth-3.17.8.tgz#b74fb5a8b6b7176d2ea8d175dcd76532caa5d367"
integrity sha512-/VkfzhYJkYW7cct0O3How5UVs4o3CG331uOrQawabeAUVXNNqnKkofFzsDX+LEhLGxwR2iwxRqszzEwSsOj0OA==
dependencies:
"@standardnotes/common" "^1.16.1"
jsonwebtoken "^8.5.1"

"@standardnotes/common@^1.16.0":
version "1.16.0"
resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.16.0.tgz#d80c00a4e7fefa6ac03946abaaffccb2fe29e882"
integrity sha512-C4Hy+G4GsKrTF4SqHrZmPu/S6eQbQC+VqlAp6BcZcEofwP7ZHVAi1todxAEED+5wPXz5VT+ctCUeoJpHtikHfA==

"@standardnotes/common@^1.16.1":
version "1.16.1"
resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.16.1.tgz#428bbd7c0ca2293e97dd0bcb033c20b3da093c16"
integrity sha512-4Uo1f0dpbWWiOVku/zxOQ7vhE5VnJbmPpWADA92Q0yTL94KRi2R39cjb/sazQqX7RVX03LpYaswyXUmH8zas1w==

"@standardnotes/[email protected]":
version "1.7.12"
resolved "https://registry.yarnpkg.com/@standardnotes/components/-/components-1.7.12.tgz#c87c3c8d90c0030b711d4f59aae47e14c745ea2a"
integrity sha512-geE3xpBagZFJCucvFymUK4qIWT45nb8OXGW8Ck0EJothVSbz4rF3MJJ/W1pvI6+kYKbT12AaUoGecL6uKxi+1Q==

"@standardnotes/domain-events@^2.25.0":
version "2.25.0"
resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.25.0.tgz#73d003967cb2b8af8afc6d26360d9af99db928fe"
integrity sha512-o9k07Urfs8u04P9TGS7vA/ol5PQ6pi7BeejHWbWInCQ/kXgHcVHJkWBPsEPRxDboLzhju7ivbzUMYlEBmkj1vw==
"@standardnotes/domain-events@^2.25.1":
version "2.25.1"
resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.25.1.tgz#3a9fa51243a036cae30beba8b83b369d598ecc80"
integrity sha512-4rOojrgVYT5QZM8kSSumP5eqGZdUjH8rs9Y7IiW5zSVi2Idq78WhLu33WTDbRn47WTsDZGkeQSRxaPPkBLabmg==
dependencies:
"@standardnotes/auth" "^3.17.7"
"@standardnotes/features" "^1.35.0"
"@standardnotes/auth" "^3.17.8"
"@standardnotes/features" "^1.35.1"

"@standardnotes/[email protected]", "@standardnotes/features@^1.35.1":
version "1.35.1"
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.35.1.tgz#1c641dc0c55cc0f90321101bb05066d008b89c92"
integrity sha512-nNyo83k+9UPOKALqJSVtqTaDq0hWHSQYlRBBQ1Vx7snC9Rxrlsgq2EO2k16ZIsRZiJbUlI0eK8uWwMey4p+L4Q==
dependencies:
"@standardnotes/auth" "^3.17.8"
"@standardnotes/common" "^1.16.1"

"@standardnotes/features@1.35.0", "@standardnotes/features@^1.35.0":
"@standardnotes/features@^1.35.0":
version "1.35.0"
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.35.0.tgz#2f3d1f1e7831ec86cf265227f4b61fbf5e245aa2"
integrity sha512-ysibgtv9KoxYsD7f77Vn4DmViDnWeLANGtGwn6uUBnQbKHzuClFmSqBfAB7rmpu+1IRc+dfL8TlkPIwY2xvWqw==
Expand All @@ -2394,6 +2422,16 @@
"@standardnotes/features" "^1.35.0"
"@standardnotes/utils" "^1.4.0"

"@standardnotes/payloads@^1.4.14":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@standardnotes/payloads/-/payloads-1.4.14.tgz#f89eebc1d3920d4759b38bfad892f821d48cf1bd"
integrity sha512-Ym9zH6IykNLNk+QrmRAaPCq5n5trLNRbWppdQmMWnQyeOOiNStd+pvVsFRCVumxDImova8KrFEdGmnTnzns+TQ==
dependencies:
"@standardnotes/applications" "^1.2.3"
"@standardnotes/common" "^1.16.1"
"@standardnotes/features" "^1.35.1"
"@standardnotes/utils" "^1.4.1"

"@standardnotes/[email protected]", "@standardnotes/responses@^1.3.14":
version "1.3.14"
resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.3.14.tgz#6a5d34490cb7a26dce0af23da8aa832aac7ca3f7"
Expand All @@ -2404,7 +2442,17 @@
"@standardnotes/features" "^1.35.0"
"@standardnotes/payloads" "^1.4.13"

"@standardnotes/[email protected]", "@standardnotes/services@^1.6.3":
"@standardnotes/responses@^1.3.15":
version "1.3.15"
resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.3.15.tgz#dd56c96fce38213603b8eaf61383e7c3ea0773d0"
integrity sha512-zJMeRxmq19RID8fLwgndVYdwMNO+y6EDTjHfKzO/ndmHY6CefNgsrVQLgcG26CIfv3Ivg4LpJLwclAmOB70Sjw==
dependencies:
"@standardnotes/auth" "^3.17.8"
"@standardnotes/common" "^1.16.1"
"@standardnotes/features" "^1.35.1"
"@standardnotes/payloads" "^1.4.14"

"@standardnotes/[email protected]":
version "1.6.3"
resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.6.3.tgz#27223ea7bb28334e3118ba9351c752b3584f3c63"
integrity sha512-p5wjHF0xaInMGQE2wVelboGp+YAYZtIQMOkA++hrIWuwziH+G+Hq2NthHtopx72kGzK8VZ+1Ay+9CRwXx+SMrg==
Expand All @@ -2414,6 +2462,16 @@
"@standardnotes/responses" "^1.3.14"
"@standardnotes/utils" "^1.4.0"

"@standardnotes/services@^1.6.4":
version "1.6.4"
resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.6.4.tgz#132836c70ed68302759e9607595c5390e8a847d5"
integrity sha512-g7NGoN1IuXYIbnIkqaQo+J2vjHtk6Yy+suI/o8as0oDAvl4ygVykEZTx6tnl4GjQblLhJK4j9za5+V9uCn1sQg==
dependencies:
"@standardnotes/applications" "^1.2.3"
"@standardnotes/common" "^1.16.1"
"@standardnotes/responses" "^1.3.15"
"@standardnotes/utils" "^1.4.1"

"@standardnotes/[email protected]", "@standardnotes/settings@^1.13.1":
version "1.13.1"
resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.13.1.tgz#c0f8558079da178667e7addd569b6953cd5e6bc2"
Expand All @@ -2433,22 +2491,22 @@
buffer "^6.0.3"
libsodium-wrappers "^0.7.9"

"@standardnotes/[email protected].2":
version "2.86.2"
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.86.2.tgz#8fd238cd49a5a2a47a20a9615d204da609000595"
integrity sha512-tM+QHmnKHf3bNYW5FHZNmW16dpaU43tjzjdD9fGLbBvWXVF+6LrZXkYopNPD3TihoIzmuR3AZddfp99UGDZyNQ==
dependencies:
"@standardnotes/applications" "^1.2.2"
"@standardnotes/auth" "^3.17.7"
"@standardnotes/common" "^1.16.0"
"@standardnotes/domain-events" "^2.25.0"
"@standardnotes/features" "^1.35.0"
"@standardnotes/payloads" "^1.4.13"
"@standardnotes/responses" "^1.3.14"
"@standardnotes/services" "^1.6.3"
"@standardnotes/[email protected].4":
version "2.86.4"
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.86.4.tgz#d0cc9d1e1e890d192bf252b19f06775902bfc6f0"
integrity sha512-Cp9nQ7a+Tjr/PVp72+qAgOaDetjyItuc9SwvnsPp4SlKku4KtCsIRQODPZfpF9ifxV/QIii+ZQbqk2ankHUQ0g==
dependencies:
"@standardnotes/applications" "^1.2.3"
"@standardnotes/auth" "^3.17.8"
"@standardnotes/common" "^1.16.1"
"@standardnotes/domain-events" "^2.25.1"
"@standardnotes/features" "^1.35.1"
"@standardnotes/payloads" "^1.4.14"
"@standardnotes/responses" "^1.3.15"
"@standardnotes/services" "^1.6.4"
"@standardnotes/settings" "^1.13.1"
"@standardnotes/sncrypto-common" "^1.7.3"
"@standardnotes/utils" "^1.4.0"
"@standardnotes/utils" "^1.4.1"

"@standardnotes/[email protected]":
version "5.17.0"
Expand All @@ -2472,6 +2530,15 @@
dompurify "^2.3.6"
lodash "^4.17.21"

"@standardnotes/utils@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@standardnotes/utils/-/utils-1.4.1.tgz#ce185e1ace6b1d4db43e7b7025747c0b7427438f"
integrity sha512-ouLfnVdwXQOBjxuxSJ9kPZmC9K+Qqq66V/Jlp0W1n6l6ywhBeS6Yv+oGTG4yvDNZeyP1myUF6VY4F9hJ8Y9wRQ==
dependencies:
"@standardnotes/common" "^1.16.1"
dompurify "^2.3.6"
lodash "^4.17.21"

"@svgr/babel-plugin-add-jsx-attribute@^6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.0.0.tgz#bd6d1ff32a31b82b601e73672a789cc41e84fe18"
Expand Down

0 comments on commit 8265d94

Please sign in to comment.