Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / shared / lib / helpers / string.ts
blobf9b3745b3185580f91b4612ebef6b3db15df0538
1 export const normalize = (value = '', removeDiacritics = false) => {
2     let normalized = value.toLowerCase().trim();
3     if (removeDiacritics) {
4         normalized = normalized.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
5     }
6     return normalized;
7 };
9 export const replaceLineBreak = (content = '') => content.replace(/(?:\r\n|\r|\n)/g, '<br />');
11 export const toCRLF = (str: string) => str.replace(/\n/g, '\r\n');
13 export const addPlus = ([first = '', ...rest] = []) => {
14     return [first, rest.length && `+${rest.length}`].filter(Boolean).join(', ');
17 export const DEFAULT_TRUNCATE_OMISSION = '…';
19 /**
20  * Given a maximum number of characters to capture from a string at the start and end of it,
21  * truncate the string by adding omission if too long. If only a maximum number of characters
22  * is passed, the string is truncated by adding omission in the middle of it if too long
23  */
24 export const truncateMore = ({
25     string,
26     charsToDisplay,
27     charsToDisplayStart = 0,
28     charsToDisplayEnd = 0,
29     omission = '…',
30     skewEnd = false,
31 }: {
32     string: string;
33     charsToDisplay?: number;
34     charsToDisplayStart?: number;
35     charsToDisplayEnd?: number;
36     omission?: string;
37     skewEnd?: boolean;
38 }): string => {
39     if (string.length === 0) {
40         return string;
41     }
43     if (charsToDisplay !== undefined) {
44         // truncate symmetrically
45         const visibleChars = charsToDisplay - omission.length;
46         const charsToDisplayStart = skewEnd ? Math.floor(visibleChars / 2) : Math.ceil(visibleChars / 2);
47         const charsToDisplayEnd = visibleChars - charsToDisplayStart;
49         return truncateMore({ string, charsToDisplayStart, charsToDisplayEnd, omission });
50     }
52     if (string.length <= charsToDisplayStart + charsToDisplayEnd + omission.length) {
53         return string;
54     }
56     const strBegin = string.substring(0, charsToDisplayStart);
57     const strEnd = string.substring(string.length - charsToDisplayEnd, string.length);
59     return strBegin + omission + strEnd;
62 export const truncatePossiblyQuotedString = (string: string, charsToDisplay: number) => {
63     const match = string.match(/^"(.+)"$/);
65     if (!match) {
66         return truncateMore({ string, charsToDisplay });
67     }
69     const [, quotedString] = match;
71     return `"${truncateMore({ string: quotedString, charsToDisplay: charsToDisplay - 2 })}"`;
74 export const getInitials = (fullName = '') => {
75     const [first, ...rest] = fullName
76         .replace(/\s{2,}/g, ' ')
77         .split(' ')
78         .filter((word = '') => !/^[.,/#!$@%^&*;:{}=\-_`~()]/g.test(word));
79     const last = rest[rest.length - 1];
81     const initials = [first, last]
82         .filter(Boolean)
83         .map((letter = '') => [...letter.toUpperCase()][0]) // We use the spread operator to support Unicode characters
84         .join('');
86     if (!initials) {
87         return '?';
88     }
90     return initials;
93 export const hasProtonDomain = (email = '') => {
94     return /@(protonmail\.(com|ch)|proton\.(me|ch)|pm\.me|)$/i.test(email);
97 const getMatchingCharacters = (string: string, substring: string) => {
98     let i;
99     for (i = 0; i < substring.length; ++i) {
100         if (string[i] !== substring[i]) {
101             return i;
102         }
103     }
104     return i > 0 ? i : 0;
107 export const findLongestMatchingIndex = (strings: string[] = [], substring = '') => {
108     let max = 0;
109     let i = -1;
111     strings.forEach((string, idx) => {
112         const numberOfMatches = getMatchingCharacters(string, substring);
113         if (numberOfMatches > max) {
114             max = numberOfMatches;
115             i = idx;
116         }
117     });
119     return i;
122 export const stripLeadingSlash = (str: string) => str.replace(/^\/+/g, '');
123 export const stripTrailingSlash = (str: string) => str.replace(/\/+$/g, '');
124 export const stripLeadingAndTrailingSlash = (str: string) => str.replace(/^\/+|\/+$/g, '');
126 export const removeDiacritics = (str: string) => {
127     return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
131  * Replace LTR and RTL override unicode chars which can lead to security issues on filenames
132  * 202D and 202E should be the only unicode chars concerned
133  * https://jira.protontech.ch/browse/SEC-644
134  */
135 export const rtlSanitize = (str: string) => {
136     return str.replace(/[\u202D\u202E]/g, '_');
139 export const removeHTMLComments = (str: string) => {
140     return str.replace(/<!--[\s\S]*?-->/g, '');