mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
99 lines
2.4 KiB
TypeScript
99 lines
2.4 KiB
TypeScript
import type {Fuse} from 'sentry/utils/fuzzySearch';
|
|
|
|
type Match = Fuse.FuseResultMatch;
|
|
|
|
type HighlightResult = {
|
|
highlight: boolean;
|
|
text: string;
|
|
};
|
|
|
|
type MatchResult = HighlightResult[];
|
|
|
|
/**
|
|
* Parses matches from fuse.js library
|
|
*
|
|
* Example `match` would be
|
|
*
|
|
* {
|
|
* value: 'Authentication tokens allow you to perform actions',
|
|
* indices: [[4, 6], [12, 13], [15, 16]],
|
|
* }
|
|
*
|
|
* So:
|
|
*
|
|
* 00-03 -> not highlighted,
|
|
* 04-06 -> highlighted,
|
|
* 07-11 -> not highlighted,
|
|
* 12-13 -> highlighted,
|
|
* ...etc
|
|
*
|
|
* @param match The match object from fuse
|
|
* @param match.value The entire string that has matches
|
|
* @param match.indices Array of indices that represent matches
|
|
*/
|
|
const getFuseMatches = ({value, indices}: Match): MatchResult => {
|
|
if (value === undefined) {
|
|
return [];
|
|
}
|
|
|
|
if (indices.length === 0) {
|
|
return [{highlight: false, text: value}];
|
|
}
|
|
|
|
const strLength = value.length;
|
|
const result: MatchResult = [];
|
|
let prev = [0, -1];
|
|
|
|
indices.forEach(([start, end]) => {
|
|
// Unhighlighted string before the match
|
|
const stringBeforeMatch = value.substring(prev[1] + 1, start);
|
|
|
|
// Only add to result if non-empty string
|
|
if (stringBeforeMatch) {
|
|
result.push({
|
|
highlight: false,
|
|
text: stringBeforeMatch,
|
|
});
|
|
}
|
|
|
|
// This is the matched string, which should be highlighted
|
|
const matchedString = value.substring(start, end + 1);
|
|
result.push({
|
|
highlight: true,
|
|
text: matchedString,
|
|
});
|
|
|
|
prev = [start, end];
|
|
});
|
|
|
|
// The rest of the string starting from the last match index
|
|
const restOfString = value.substring(prev[1] + 1, strLength);
|
|
// Only add to result if non-empty string
|
|
if (restOfString) {
|
|
result.push({highlight: false, text: restOfString});
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
type MarkProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
|
|
/**
|
|
* Given a match object from fuse.js, returns an array of components with
|
|
* "highlighted" (bold) substrings.
|
|
*/
|
|
const highlightFuseMatches = (matchObj: Match, Marker: React.ComponentType<MarkProps>) =>
|
|
getFuseMatches(matchObj).map(({highlight, text}, index) => {
|
|
if (!text) {
|
|
return null;
|
|
}
|
|
if (highlight) {
|
|
return <Marker key={index}>{text}</Marker>;
|
|
}
|
|
|
|
return <span key={index}>{text}</span>;
|
|
});
|
|
|
|
export {getFuseMatches};
|
|
export default highlightFuseMatches;
|