import { escape } from './escape-html';
import { isPlainObject } from './isPlainObject';
import type { Hit, FacetHit, EscapedHits } from '../../types';
export const TAG_PLACEHOLDER = {
highlightPreTag: '__ais-highlight__',
highlightPostTag: '__/ais-highlight__',
};
export const TAG_REPLACEMENT = {
highlightPreTag: '',
highlightPostTag: '',
};
function replaceTagsAndEscape(value: string): string {
return escape(value)
.replace(
new RegExp(TAG_PLACEHOLDER.highlightPreTag, 'g'),
TAG_REPLACEMENT.highlightPreTag
)
.replace(
new RegExp(TAG_PLACEHOLDER.highlightPostTag, 'g'),
TAG_REPLACEMENT.highlightPostTag
);
}
function recursiveEscape(input: any): any {
if (isPlainObject(input) && typeof input.value !== 'string') {
return Object.keys(input).reduce(
(acc, key) => ({
...acc,
[key]: recursiveEscape(input[key]),
}),
{}
);
}
if (Array.isArray(input)) {
return input.map(recursiveEscape);
}
return {
...input,
value: replaceTagsAndEscape(input.value),
};
}
export function escapeHits(
hits: THit[] | EscapedHits
): EscapedHits {
if ((hits as EscapedHits).__escaped === undefined) {
// We don't override the value on hit because it will mutate the raw results
// instead we make a shallow copy and we assign the escaped values on it.
hits = hits.map(({ ...hit }) => {
if (hit._highlightResult) {
hit._highlightResult = recursiveEscape(hit._highlightResult);
}
if (hit._snippetResult) {
hit._snippetResult = recursiveEscape(hit._snippetResult);
}
return hit;
});
(hits as EscapedHits).__escaped = true;
}
return hits as EscapedHits;
}
export function escapeFacets(facetHits: FacetHit[]): FacetHit[] {
return facetHits.map((h) => ({
...h,
highlighted: replaceTagsAndEscape(h.highlighted),
}));
}