Skip to content

Commit f80af1c

Browse files
feat(string helpers): add string manipulation functions and tests
Release-As: 0.2.1
1 parent c1ad315 commit f80af1c

3 files changed

Lines changed: 107 additions & 0 deletions

File tree

β€Žpackages/helpers/src/index.jsβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './is.js';
33
export * from './merge.js';
44
export * from './noop.js';
55
export * from './splitConfig.js';
6+
export * from './strings.js';
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const invisibleCharRegex = '[\\s\\p{C}\u034f\u17b4\u17b5\u2800\u115f\u1160\u3164\uffa0]';
2+
const trimStartRegex = new RegExp('^' + invisibleCharRegex, 'u');
3+
const trimEndRegex = new RegExp(invisibleCharRegex + '$', 'u');
4+
5+
export function trimStart(str) {
6+
while (trimStartRegex.test(str)) {
7+
str = str.replace(trimStartRegex, '');
8+
}
9+
10+
return str;
11+
}
12+
13+
export function trimEnd(str) {
14+
while (trimEndRegex.test(str)) {
15+
str = str.replace(trimEndRegex, '');
16+
}
17+
18+
return str;
19+
}
20+
21+
const graphemeSegmenter = new Intl.Segmenter({ granularity: 'grapheme' });
22+
23+
export function truncate(str, maxLength) {
24+
if (!maxLength) return str;
25+
if (str.length <= maxLength) return str;
26+
27+
const graphemes = Array.from(graphemeSegmenter.segment(str), (s) => s.segment);
28+
if (graphemes.length <= maxLength) return str;
29+
30+
return trimEnd(graphemes.slice(0, maxLength - 3).join('')) + '...';
31+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { trimEnd, trimStart, truncate } from './strings.js';
2+
3+
describe('helpers', () => {
4+
describe('trimStart', () => {
5+
it('should remove invisible characters from the start of a string', () => {
6+
const input = '\u034f\u034fHello';
7+
const result = trimStart(input);
8+
expect(result).toBe('Hello');
9+
});
10+
11+
it('should return the same string if no invisible characters are at the start', () => {
12+
const input = 'Hello';
13+
const result = trimStart(input);
14+
expect(result).toBe('Hello');
15+
});
16+
});
17+
18+
describe('trimEnd', () => {
19+
it('should remove invisible characters from the end of a string', () => {
20+
const input = 'Hello\u034f\u034f';
21+
const result = trimEnd(input);
22+
expect(result).toBe('Hello');
23+
});
24+
25+
it('should return the same string if no invisible characters are at the end', () => {
26+
const input = 'Hello';
27+
const result = trimEnd(input);
28+
expect(result).toBe('Hello');
29+
});
30+
});
31+
32+
describe('truncate', () => {
33+
it('should truncate a string to the specified maxLength and append "..."', () => {
34+
const input = 'This is a long string.';
35+
const result = truncate(input, 10);
36+
expect(result).toBe('This is...');
37+
});
38+
39+
it('should return the original string if it is shorter than maxLength', () => {
40+
const input = 'Short';
41+
const result = truncate(input, 10);
42+
expect(result).toBe('Short');
43+
});
44+
45+
it('should return the original string if maxLength is not provided', () => {
46+
const input = 'No max length';
47+
const result = truncate(input);
48+
expect(result).toBe('No max length');
49+
});
50+
51+
it('should return the original string if maxLength is 0', () => {
52+
const input = 'No max length';
53+
const result = truncate(input, 0);
54+
expect(result).toBe('No max length');
55+
});
56+
57+
it('should handle emojis correctly', () => {
58+
const input = 'πŸ˜€ This is a long string with emojis.';
59+
const result = truncate(input, 12);
60+
expect(result).toBe('πŸ˜€ This is...');
61+
});
62+
63+
it('should handle emojis at the truncation point', () => {
64+
const emoji = 'πŸ‘©β€β€οΈβ€πŸ’‹β€πŸ‘¨';
65+
expect(emoji).toHaveLength(11);
66+
const input = `Truncate this ${emoji} string.`;
67+
68+
expect(truncate(input, 16)).toBe('Truncate this...');
69+
expect(truncate(input, 17)).toBe('Truncate this...');
70+
expect(truncate(input, 18)).toBe('Truncate this πŸ‘©β€β€οΈβ€πŸ’‹β€πŸ‘¨...');
71+
expect(truncate(input, 19)).toBe('Truncate this πŸ‘©β€β€οΈβ€πŸ’‹β€πŸ‘¨...');
72+
expect(truncate(input, 20)).toBe('Truncate this πŸ‘©β€β€οΈβ€πŸ’‹β€πŸ‘¨ s...');
73+
});
74+
});
75+
});

0 commit comments

Comments
Β (0)