Skip to content

Commit d86a33a

Browse files
authored
feat(reverseHighlight/reverseSnippet): implement sibling strategy from InstantSearch.js (#388)
* Implement sibling strategy from InstantSearch.js * Increase bundle size * Rename `getHighlightFromSiblings` to `isPartHighlighted`
1 parent d23f133 commit d86a33a

File tree

6 files changed

+173
-3
lines changed

6 files changed

+173
-3
lines changed

bundlesize.config.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
},
77
{
88
"path": "packages/autocomplete-js/dist/umd/index.production.js",
9-
"maxSize": "10 kB"
9+
"maxSize": "10.1 kB"
1010
},
1111
{
1212
"path": "packages/autocomplete-preset-algolia/dist/umd/index.production.js",
@@ -22,7 +22,7 @@
2222
},
2323
{
2424
"path": "packages/autocomplete-plugin-query-suggestions/dist/umd/index.production.js",
25-
"maxSize": "2.25 kB"
25+
"maxSize": "2.3 kB"
2626
}
2727
]
2828
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { reverseHighlightHit } from '../highlight';
2+
3+
describe('reverseHighlightHit', () => {
4+
test('returns a reversed partially highlighted hit', () => {
5+
expect(
6+
reverseHighlightHit({
7+
hit: {
8+
objectID: 'amazon fire tablets',
9+
query: 'amazon fire tablets',
10+
_highlightResult: {
11+
query: {
12+
fullyHighlighted: false,
13+
matchLevel: 'full',
14+
matchedWords: ['fire', 'tablet'],
15+
value:
16+
'amazon __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablet__/aa-highlight__s',
17+
},
18+
},
19+
},
20+
attribute: 'query',
21+
})
22+
).toMatchInlineSnapshot(`"<mark>amazon </mark>fire tablet<mark>s</mark>"`);
23+
});
24+
25+
test('returns a reversed fully highlighted hit', () => {
26+
expect(
27+
reverseHighlightHit({
28+
hit: {
29+
objectID: 'amazon fire tablets',
30+
query: 'amazon fire tablets',
31+
_highlightResult: {
32+
query: {
33+
fullyHighlighted: true,
34+
matchLevel: 'full',
35+
matchedWords: ['amazon', 'fire', 'tablet'],
36+
value:
37+
'__aa-highlight__amazon__/aa-highlight__ __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablets__/aa-highlight__',
38+
},
39+
},
40+
},
41+
attribute: 'query',
42+
})
43+
).toMatchInlineSnapshot(`"amazon fire tablets"`);
44+
});
45+
46+
test('returns a reversed empty highlighted query hit', () => {
47+
expect(
48+
reverseHighlightHit({
49+
hit: {
50+
objectID: 'amazon fire tablets',
51+
query: 'amazon fire tablets',
52+
_highlightResult: {
53+
query: {
54+
fullyHighlighted: false,
55+
matchLevel: 'none',
56+
matchedWords: [],
57+
value: 'amazon fire tablets',
58+
},
59+
},
60+
},
61+
attribute: 'query',
62+
})
63+
).toMatchInlineSnapshot(`"amazon fire tablets"`);
64+
});
65+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { isPartHighlighted } from '../isPartHighlighted';
2+
3+
describe('isPartHighlighted', () => {
4+
test('returns the isHighlighted value with a missing sibling', () => {
5+
expect(
6+
isPartHighlighted(
7+
[
8+
{ isHighlighted: true, value: 'Amazon' },
9+
{
10+
isHighlighted: false,
11+
value: ' - Fire HD8 - 8&quot; - Tablet - 16GB - Wi-Fi - Black',
12+
},
13+
],
14+
0
15+
)
16+
).toEqual(true);
17+
});
18+
19+
test('returns the isHighlighted value with both siblings', () => {
20+
expect(
21+
isPartHighlighted(
22+
[
23+
{ isHighlighted: true, value: 'Amazon' },
24+
{ isHighlighted: false, value: ' - ' },
25+
{ isHighlighted: true, value: 'Fire' },
26+
{ isHighlighted: false, value: ' ' },
27+
{ isHighlighted: true, value: 'TV' },
28+
],
29+
1
30+
)
31+
).toEqual(true);
32+
});
33+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { reverseHighlightedParts } from '../reverseHighlightedParts';
2+
3+
describe('reverseHighlightedParts', () => {
4+
test('returns a reversed partially highlighted parts array', () => {
5+
expect(
6+
reverseHighlightedParts([
7+
{ isHighlighted: true, value: 'amazon ((fire' },
8+
{ isHighlighted: false, value: 'tv)) tablet??' },
9+
])
10+
).toEqual([
11+
{ isHighlighted: false, value: 'amazon ((fire' },
12+
{ isHighlighted: true, value: 'tv)) tablet??' },
13+
]);
14+
});
15+
16+
test('returns a reversed fully highlighted parts array', () => {
17+
expect(
18+
reverseHighlightedParts([
19+
{ isHighlighted: true, value: 'amazon ((fire tv)) tablet??' },
20+
])
21+
).toEqual([{ isHighlighted: false, value: 'amazon ((fire tv)) tablet??' }]);
22+
});
23+
24+
test('returns a reversed highlighted parts array based on sibling highlighting', () => {
25+
expect(
26+
reverseHighlightedParts([
27+
{ isHighlighted: true, value: 'amazon ((fire tv)) tablet' },
28+
{ isHighlighted: false, value: '??' },
29+
])
30+
).toEqual([
31+
{ isHighlighted: false, value: 'amazon ((fire tv)) tablet' },
32+
{ isHighlighted: false, value: '??' },
33+
]);
34+
});
35+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { ParsedAttribute } from './ParsedAttribute';
2+
3+
const htmlEscapes = {
4+
'&amp;': '&',
5+
'&lt;': '<',
6+
'&gt;': '>',
7+
'&quot;': '"',
8+
'&#39;': "'",
9+
};
10+
const hasAlphanumeric = new RegExp(/\w/i);
11+
const regexEscapedHtml = /&(amp|quot|lt|gt|#39);/g;
12+
const regexHasEscapedHtml = RegExp(regexEscapedHtml.source);
13+
14+
function unescape(value: string): string {
15+
return value && regexHasEscapedHtml.test(value)
16+
? value.replace(regexEscapedHtml, (character) => htmlEscapes[character])
17+
: value;
18+
}
19+
20+
export function isPartHighlighted(parts: ParsedAttribute[], i: number) {
21+
const current = parts[i];
22+
const isNextHighlighted = parts[i + 1]?.isHighlighted || true;
23+
const isPreviousHighlighted = parts[i - 1]?.isHighlighted || true;
24+
25+
if (
26+
!hasAlphanumeric.test(unescape(current.value)) &&
27+
isPreviousHighlighted === isNextHighlighted
28+
) {
29+
return isPreviousHighlighted;
30+
}
31+
32+
return current.isHighlighted;
33+
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isPartHighlighted } from './isPartHighlighted';
12
import { ParsedAttribute } from './ParsedAttribute';
23

34
export function reverseHighlightedParts(parts: ParsedAttribute[]) {
@@ -6,5 +7,8 @@ export function reverseHighlightedParts(parts: ParsedAttribute[]) {
67
return parts.map((part) => ({ ...part, isHighlighted: false }));
78
}
89

9-
return parts.map((part) => ({ ...part, isHighlighted: !part.isHighlighted }));
10+
return parts.map((part, i) => ({
11+
...part,
12+
isHighlighted: !isPartHighlighted(parts, i),
13+
}));
1014
}

0 commit comments

Comments
 (0)