signal-desktop/ts/util/graphemeAndLinkAwareSlice.ts

71 lines
1.4 KiB
TypeScript
Raw Normal View History

2023-01-03 19:55:46 +00:00
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import LinkifyIt from 'linkify-it';
export function graphemeAndLinkAwareSlice(
str: string,
length: number,
buffer = 100
): {
hasReadMore: boolean;
text: string;
} {
if (str.length <= length + buffer) {
return { text: str, hasReadMore: false };
}
let text: string | undefined;
for (const { index } of new Intl.Segmenter().segment(str)) {
if (!text && index >= length) {
text = str.slice(0, index);
}
if (text && index > length) {
text = expandToIncludeEntireLink(str, text);
return {
text,
hasReadMore: text.length < str.length,
};
}
}
return {
text: str,
hasReadMore: false,
};
}
const expandToIncludeEntireLink = (
original: string,
truncated: string
): string => {
const linksInText = new LinkifyIt().match(original);
if (!linksInText) {
return truncated;
}
const invalidTruncationRanges: Array<LinkRange> = linksInText.map(
({ index: startIndex, lastIndex }) => ({ startIndex, lastIndex })
);
const truncatedLink: Array<LinkRange> = invalidTruncationRanges.filter(
({ startIndex, lastIndex }) =>
startIndex < truncated.length && lastIndex > truncated.length
);
2022-12-12 23:35:32 +00:00
if (truncatedLink.length === 0) {
return truncated;
}
return original.slice(0, truncatedLink[0].lastIndex);
};
type LinkRange = {
startIndex: number;
lastIndex: number;
};