Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- `splitLines` string utility function
- `trimStart`, `trimEnd` and `trim` string type utility functions

### Changed

Expand Down
38 changes: 37 additions & 1 deletion src/lib/string.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isNullOrEmpty, isNullOrWhitespace, capitalize, uncapitalize, truncate, splitLines } from "./string";
import { isNullOrEmpty, isNullOrWhitespace, capitalize, uncapitalize, truncate, splitLines, trimStart, trimEnd, trim } from "./string";

describe("string tests", () => {
test.each([
Expand Down Expand Up @@ -121,6 +121,42 @@ describe("string tests", () => {
expect(truncate(value, maxLength)).toBe(expected);
});

test.each([
[null as unknown as string, " ", null as unknown as string],
[undefined as unknown as string, " ", undefined as unknown as string],
["hello world", "hello world", ""],
["hello world", " ", "hello world"],
[" hello world", " ", "hello world"],
["hello world hello world", "hello world", " hello world"],
["hello worldhello world", "hello world", ""],
])("left trim", (haystack, needle, expected) => {
expect(trimStart(haystack, needle)).toBe(expected);
});

test.each([
[null as unknown as string, " ", null as unknown as string],
[undefined as unknown as string, " ", undefined as unknown as string],
["hello world", "hello world", ""],
["hello world ", " ", "hello world"],
["hello world", " ", "hello world"],
["hello world hello world", "hello world", "hello world "],
["hello worldhello world", "hello world", ""],
])("right trim", (haystack, needle, expected) => {
expect(trimEnd(haystack, needle)).toBe(expected);
});

test.each([
[null as unknown as string, " ", null as unknown as string],
[undefined as unknown as string, " ", undefined as unknown as string],
["hello world", "", "hello world"],
[" hello world ", " ", "hello world"],
["hello world ", " ", "hello world"],
[" hello world", " ", "hello world"],
["hello worldhello world", "hello world", ""],
])("trim", (haystack, needle, expected) => {
expect(trim(haystack, needle)).toBe(expected);
});

test.each([
["", false, false, []],
[null as unknown as string, false, false, []],
Expand Down
58 changes: 58 additions & 0 deletions src/lib/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,64 @@ export function truncate(value: string | undefined, maxLength: number, suffix =
return `${value.slice(0, maxLength)}${suffix}`;
}

/**
* Removes all occurrences of needle from the start of haystack
* @param haystack string to trim
* @param needle the thing to trim
* @returns the string trimmed from the left side
*/
export function trimStart(haystack: string, needle: string): string {
if (isNullOrEmpty(haystack) || isNullOrEmpty(needle)) {
return haystack;
}

let offset = 0;

while (haystack.indexOf(needle, offset) === offset) {
offset = offset + needle.length;
}
return haystack.slice(offset);
}

/**
* Removes all occurrences of needle from the end of haystack
* @param haystack string to trim
* @param needle the thing to trim
* @returns the string trimmed from the right side
*/
export function trimEnd(haystack: string, needle: string): string {
if (isNullOrEmpty(haystack) || isNullOrEmpty(needle)) {
return haystack;
}

let offset = haystack.length,
idx = -1;

while (true) {
idx = haystack.lastIndexOf(needle, offset - 1);
if (idx === -1 || idx + needle.length !== offset) {
break;
}
if (idx === 0) {
return "";
}
offset = idx;
}

return haystack.slice(0, offset);
}

/**
* Removes all occurrences of needle from the start and the end of haystack
* @param haystack string to trim
* @param needle the thing to trim
* @returns the string trimmed from the right and left side
*/
export function trim(haystack: string, needle: string): string {
const trimmed = trimStart(haystack, needle);
return trimEnd(trimmed, needle);
}

/**
* Splits the string at line breaks
* @param str the string to split
Expand Down
Loading