| /** | |
| * String utility functions for common text operations | |
| */ | |
| /** | |
| * Truncate a string to a maximum length, adding an ellipsis if truncated | |
| * @param str - The string to truncate | |
| * @param maxLength - Maximum length of the result (including ellipsis) | |
| * @param ellipsis - The ellipsis string to use (default: '...') | |
| * @returns The truncated string | |
| */ | |
| export function truncate(str: string, maxLength: number, ellipsis: string = '...'): string { | |
| if (maxLength < ellipsis.length) { | |
| throw new Error( | |
| `maxLength (${maxLength}) must be at least the length of ellipsis (${ellipsis.length})` | |
| ); | |
| } | |
| if (str.length <= maxLength) { | |
| return str; | |
| } | |
| return str.slice(0, maxLength - ellipsis.length) + ellipsis; | |
| } | |
| /** | |
| * Convert a string to kebab-case (e.g., "Hello World" -> "hello-world") | |
| * @param str - The string to convert | |
| * @returns The kebab-case string | |
| */ | |
| export function toKebabCase(str: string): string { | |
| return str | |
| .replace(/([a-z])([A-Z])/g, '$1-$2') // camelCase -> camel-Case | |
| .replace(/[\s_]+/g, '-') // spaces and underscores -> hyphens | |
| .replace(/[^a-zA-Z0-9-]/g, '') // remove non-alphanumeric (except hyphens) | |
| .replace(/-+/g, '-') // collapse multiple hyphens | |
| .replace(/^-|-$/g, '') // remove leading/trailing hyphens | |
| .toLowerCase(); | |
| } | |
| /** | |
| * Convert a string to camelCase (e.g., "hello-world" -> "helloWorld") | |
| * @param str - The string to convert | |
| * @returns The camelCase string | |
| */ | |
| export function toCamelCase(str: string): string { | |
| return str | |
| .replace(/[^a-zA-Z0-9\s_-]/g, '') // remove special characters | |
| .replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : '')) | |
| .replace(/^[A-Z]/, (char) => char.toLowerCase()); | |
| } | |
| /** | |
| * Convert a string to PascalCase (e.g., "hello-world" -> "HelloWorld") | |
| * @param str - The string to convert | |
| * @returns The PascalCase string | |
| */ | |
| export function toPascalCase(str: string): string { | |
| const camel = toCamelCase(str); | |
| return camel.charAt(0).toUpperCase() + camel.slice(1); | |
| } | |
| /** | |
| * Capitalize the first letter of a string | |
| * @param str - The string to capitalize | |
| * @returns The string with first letter capitalized | |
| */ | |
| export function capitalize(str: string): string { | |
| if (str.length === 0) { | |
| return str; | |
| } | |
| return str.charAt(0).toUpperCase() + str.slice(1); | |
| } | |
| /** | |
| * Remove duplicate whitespace from a string, preserving single spaces | |
| * @param str - The string to clean | |
| * @returns The string with duplicate whitespace removed | |
| */ | |
| export function collapseWhitespace(str: string): string { | |
| return str.replace(/\s+/g, ' ').trim(); | |
| } | |
| /** | |
| * Check if a string is empty or contains only whitespace | |
| * @param str - The string to check | |
| * @returns True if the string is blank | |
| */ | |
| export function isBlank(str: string | null | undefined): boolean { | |
| return str === null || str === undefined || str.trim().length === 0; | |
| } | |
| /** | |
| * Check if a string is not empty and contains non-whitespace characters | |
| * @param str - The string to check | |
| * @returns True if the string is not blank | |
| */ | |
| export function isNotBlank(str: string | null | undefined): boolean { | |
| return !isBlank(str); | |
| } | |
| /** | |
| * Safely parse a string to an integer, returning a default value on failure | |
| * @param str - The string to parse | |
| * @param defaultValue - The default value if parsing fails (default: 0) | |
| * @returns The parsed integer or the default value | |
| */ | |
| export function safeParseInt(str: string | null | undefined, defaultValue: number = 0): number { | |
| if (isBlank(str)) { | |
| return defaultValue; | |
| } | |
| const parsed = parseInt(str!, 10); | |
| return isNaN(parsed) ? defaultValue : parsed; | |
| } | |
| /** | |
| * Generate a slug from a string (URL-friendly identifier) | |
| * @param str - The string to convert to a slug | |
| * @param maxLength - Optional maximum length for the slug | |
| * @returns The slugified string | |
| */ | |
| export function slugify(str: string, maxLength?: number): string { | |
| let slug = str | |
| .toLowerCase() | |
| .normalize('NFD') // Normalize unicode characters | |
| .replace(/[\u0300-\u036f]/g, '') // Remove diacritics | |
| .replace(/[^a-z0-9\s-]/g, '') // Remove non-alphanumeric | |
| .replace(/\s+/g, '-') // Replace spaces with hyphens | |
| .replace(/-+/g, '-') // Collapse multiple hyphens | |
| .replace(/^-|-$/g, ''); // Remove leading/trailing hyphens | |
| if (maxLength !== undefined && slug.length > maxLength) { | |
| // Truncate at word boundary if possible | |
| slug = slug.slice(0, maxLength); | |
| const lastHyphen = slug.lastIndexOf('-'); | |
| if (lastHyphen > maxLength * 0.5) { | |
| slug = slug.slice(0, lastHyphen); | |
| } | |
| slug = slug.replace(/-$/g, ''); // Remove trailing hyphen after truncation | |
| } | |
| return slug; | |
| } | |
| /** | |
| * Escape special regex characters in a string | |
| * @param str - The string to escape | |
| * @returns The escaped string safe for use in a RegExp | |
| */ | |
| export function escapeRegex(str: string): string { | |
| return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); | |
| } | |
| /** | |
| * Pluralize a word based on count | |
| * @param word - The singular form of the word | |
| * @param count - The count to base pluralization on | |
| * @param pluralForm - Optional custom plural form (default: word + 's') | |
| * @returns The word in singular or plural form | |
| */ | |
| export function pluralize(word: string, count: number, pluralForm?: string): string { | |
| if (count === 1) { | |
| return word; | |
| } | |
| return pluralForm || `${word}s`; | |
| } | |
| /** | |
| * Format a count with its associated word (e.g., "1 item", "3 items") | |
| * @param count - The count | |
| * @param singular - The singular form of the word | |
| * @param plural - Optional custom plural form | |
| * @returns Formatted string with count and word | |
| */ | |
| export function formatCount(count: number, singular: string, plural?: string): string { | |
| return `${count} ${pluralize(singular, count, plural)}`; | |
| } | |