7 export const normalize = (value = '', removeDiacritics = false) => {
8 let normalized = value.toLowerCase().trim();
9 if (removeDiacritics) {
10 normalized = normalized.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
15 export const replaceLineBreak = (content = '') => content.replace(/(?:\r\n|\r|\n)/g, '<br />');
17 export const toCRLF = (str: string) => str.replace(/\n/g, '\r\n');
19 export const toPrice = (amount = 0, currency: keyof typeof CURRENCIES = 'EUR', divisor = 100) => {
20 const symbol = CURRENCIES[currency] || currency;
21 const value = Number(amount / divisor).toFixed(2);
22 const prefix = +value < 0 ? '-' : '';
23 const absValue = Math.abs(+value);
25 if (currency === 'USD') {
26 return `${prefix}${symbol}${absValue}`;
29 return `${prefix}${absValue} ${symbol}`;
32 export const addPlus = ([first = '', ...rest] = []) => {
33 return [first, rest.length && `+${rest.length}`].filter(Boolean).join(', ');
36 export const DEFAULT_TRUNCATE_OMISSION = '…';
39 * Given a maximum number of characters to capture from a string at the start and end of it,
40 * truncate the string by adding omission if too long. If only a maximum number of characters
41 * is passed, the string is truncated by adding omission in the middle of it if too long
43 export const truncateMore = ({
46 charsToDisplayStart = 0,
47 charsToDisplayEnd = 0,
52 charsToDisplay?: number;
53 charsToDisplayStart?: number;
54 charsToDisplayEnd?: number;
58 if (string.length === 0) {
62 if (charsToDisplay !== undefined) {
63 // truncate symmetrically
64 const visibleChars = charsToDisplay - omission.length;
65 const charsToDisplayStart = skewEnd ? Math.floor(visibleChars / 2) : Math.ceil(visibleChars / 2);
66 const charsToDisplayEnd = visibleChars - charsToDisplayStart;
68 return truncateMore({ string, charsToDisplayStart, charsToDisplayEnd, omission });
71 if (string.length <= charsToDisplayStart + charsToDisplayEnd + omission.length) {
75 const strBegin = string.substring(0, charsToDisplayStart);
76 const strEnd = string.substring(string.length - charsToDisplayEnd, string.length);
78 return strBegin + omission + strEnd;
81 export const truncatePossiblyQuotedString = (string: string, charsToDisplay: number) => {
82 const match = string.match(/^"(.+)"$/);
85 return truncateMore({ string, charsToDisplay });
88 const [, quotedString] = match;
90 return `"${truncateMore({ string: quotedString, charsToDisplay: charsToDisplay - 2 })}"`;
93 export const getInitials = (fullName = '') => {
94 const [first, ...rest] = fullName
95 .replace(/\s{2,}/g, ' ')
97 .filter((word = '') => !/^[.,/#!$@%^&*;:{}=\-_`~()]/g.test(word));
98 const last = rest[rest.length - 1];
100 const initials = [first, last]
102 .map((letter = '') => [...letter.toUpperCase()][0]) // We use the spread operator to support Unicode characters
112 export const hasProtonDomain = (email = '') => {
113 return /@(protonmail\.(com|ch)|proton\.(me|ch)|pm\.me|)$/i.test(email);
116 const getMatchingCharacters = (string: string, substring: string) => {
118 for (i = 0; i < substring.length; ++i) {
119 if (string[i] !== substring[i]) {
123 return i > 0 ? i : 0;
126 export const findLongestMatchingIndex = (strings: string[] = [], substring = '') => {
130 strings.forEach((string, idx) => {
131 const numberOfMatches = getMatchingCharacters(string, substring);
132 if (numberOfMatches > max) {
133 max = numberOfMatches;
141 export const stripLeadingSlash = (str: string) => str.replace(/^\/+/g, '');
142 export const stripTrailingSlash = (str: string) => str.replace(/\/+$/g, '');
143 export const stripLeadingAndTrailingSlash = (str: string) => str.replace(/^\/+|\/+$/g, '');
145 export const removeDiacritics = (str: string) => {
146 return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
150 * Replace LTR and RTL override unicode chars which can lead to security issues on filenames
151 * 202D and 202E should be the only unicode chars concerned
152 * https://jira.protontech.ch/browse/SEC-644
154 export const rtlSanitize = (str: string) => {
155 return str.replace(/[\u202D\u202E]/g, '_');
158 export const removeHTMLComments = (str: string) => {
159 return str.replace(/<!--[\s\S]*?-->/g, '');