{"version":3,"file":"StringUtils.mjs","sources":["../src/StringUtils.ts"],"sourcesContent":["/**\n * @module StringUtils\n * @description A comprehensive collection of utility functions for string manipulation, formatting, and validation.\n * @example\n * ```typescript\n * import { StringUtils } from 'houser-js-utils';\n *\n * // Convert camelCase to sentence\n * const sentence = StringUtils.camelCaseToSentence('myVariableName'); // \"My Variable Name\"\n *\n * // Capitalize words\n * const title = StringUtils.capitalizeWords('hello world'); // \"Hello World\"\n *\n * // Format bytes\n * const size = StringUtils.formatBytes(1024); // \"1 KB\"\n * ```\n */\n\nexport const StringUtils = {\n  /**\n   * Converts a camelCase string to a sentence with proper capitalization.\n   * @param str - The camelCase string to convert\n   * @returns The converted sentence with proper spacing and capitalization\n   * @example\n   * ```typescript\n   * StringUtils.camelCaseToSentence('myVariableName'); // Returns \"My Variable Name\"\n   * StringUtils.camelCaseToSentence('XMLHttpRequest'); // Returns \"XML Http Request\"\n   * ```\n   */\n  camelCaseToSentence: (str: string): string => {\n    if (!StringUtils.isString(str)) {\n      return \"\";\n    }\n\n    const result = str\n      .replace(/_/g, \" \") // Replace underscores with spaces\n      .replace(/([a-z])([A-Z])/g, \"$1 $2\") // Add spaces between camelCased words\n      .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\") // Handle special cases for acronyms\n      .replace(/(\\d+)([A-Z][a-z]*)/, \"$1 $2\") // Add space between numbers and following camelCase words\n      .replace(/(\\d+)/g, \" $1\") // Add spaces before numbers\n      .trim();\n\n    return StringUtils.capitalizeWords(result);\n  },\n\n  /**\n   * Converts a string to camelCase format.\n   * @param str - The string to convert to camelCase\n   * @returns The camelCased string\n   * @example\n   * ```typescript\n   * StringUtils.camelize('hello world'); // Returns \"helloWorld\"\n   * StringUtils.camelize('my-variable-name'); // Returns \"myVariableName\"\n   * ```\n   */\n  camelize: (str: string): string => {\n    return str\n      .toLowerCase()\n      .replace(/^([a-zA-Z0-9]+)|[\\s-_]+(\\w)/g, (_match, p1, p2) => {\n        if (p2) return p2.toUpperCase();\n        return p1.toLowerCase();\n      });\n  },\n\n  /**\n   * Capitalizes the first letter of a string.\n   * @param str - The string to capitalize\n   * @returns The string with the first letter capitalized\n   * @example\n   * ```typescript\n   * StringUtils.capitalize('hello'); // Returns \"Hello\"\n   * StringUtils.capitalize('WORLD'); // Returns \"WORLD\"\n   * ```\n   */\n  capitalize: (str: string): string => {\n    if (!StringUtils.isString(str)) {\n      return \"\";\n    }\n\n    return str.charAt(0).toUpperCase() + str.slice(1);\n  },\n\n  /**\n   * Capitalizes the first letter of each word in a string.\n   * @param str - The string to convert to title case\n   * @returns The string with each word capitalized\n   * @example\n   * ```typescript\n   * StringUtils.capitalizeWords('hello world'); // Returns \"Hello World\"\n   * StringUtils.capitalizeWords('the quick brown fox'); // Returns \"The Quick Brown Fox\"\n   * ```\n   */\n  capitalizeWords: (str: string): string => {\n    if (!StringUtils.isString(str)) {\n      return \"\";\n    }\n\n    return str\n      .toLowerCase()\n      .replace(/\\s+/g, \" \") // Normalize multiple spaces into single spaces\n      .split(\" \")\n      .map((word) => StringUtils.capitalize(word))\n      .join(\" \");\n  },\n\n  /**\n   * Checks if a string contains another string (case-insensitive).\n   * @param haystack - The string to search in\n   * @param needle - The string to search for\n   * @returns True if the haystack contains the needle, false otherwise\n   * @example\n   * ```typescript\n   * StringUtils.contains('Hello World', 'world'); // Returns true\n   * StringUtils.contains('JavaScript', 'script'); // Returns true\n   * StringUtils.contains('TypeScript', 'python'); // Returns false\n   * ```\n   */\n  contains: (haystack: unknown, needle: unknown): boolean => {\n    const hayStackStr = StringUtils.toString(haystack);\n    const needleStr = StringUtils.toString(needle);\n\n    if (!hayStackStr) return false;\n    if (!needleStr) return true;\n\n    return hayStackStr.toLowerCase().includes(needleStr.toLowerCase());\n  },\n\n  /**\n   * Formats a number of bytes into a human-readable string with appropriate units.\n   * @param bytes - The number of bytes to format\n   * @param decimals - The number of decimal places to include (default: 0)\n   * @returns A formatted string with appropriate byte units\n   * @example\n   * ```typescript\n   * StringUtils.formatBytes(1024); // Returns \"1 KB\"\n   * StringUtils.formatBytes(1536, 1); // Returns \"1.5 KB\"\n   * StringUtils.formatBytes(1048576); // Returns \"1 MB\"\n   * ```\n   */\n  formatBytes: (bytes: number, decimals = 0): string => {\n    if (bytes === 0) return \"0 Bytes\";\n\n    const k = 1024;\n    const dm = decimals < 0 ? 0 : decimals;\n    const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n\n    const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n    return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;\n  },\n\n  /**\n   * Type guard to check if a value is a string.\n   * @param value - The value to check\n   * @returns True if the value is a string, false otherwise\n   * @example\n   * ```typescript\n   * StringUtils.isString('hello'); // Returns true\n   * StringUtils.isString(123); // Returns false\n   * StringUtils.isString(null); // Returns false\n   * ```\n   */\n  isString: (value: unknown): value is string => typeof value === \"string\",\n\n  /**\n   * Gets the length of a string safely.\n   * @param str - The string to measure\n   * @returns The length of the string, or 0 if the string is null/undefined\n   * @example\n   * ```typescript\n   * StringUtils.length('hello'); // Returns 5\n   * StringUtils.length(''); // Returns 0\n   * StringUtils.length(null); // Returns 0\n   * ```\n   */\n  length: (str: string): number => {\n    return str ? str.length : 0;\n  },\n\n  /**\n   * Truncates a string in the middle with ellipsis if it exceeds the maximum length.\n   * @param str - The string to truncate (default: empty string)\n   * @param maxLength - The maximum length before truncation (default: 20)\n   * @returns The truncated string with ellipsis in the middle\n   * @example\n   * ```typescript\n   * StringUtils.middleEllipsify('verylongfilename.txt', 15); // Returns \"veryl...me.txt\"\n   * StringUtils.middleEllipsify('short.txt', 20); // Returns \"short.txt\"\n   * ```\n   */\n  middleEllipsify: (str: string = \"\", maxLength = 20): string => {\n    const strParam = StringUtils.toString(str);\n\n    if (strParam.length > maxLength && maxLength > 5) {\n      return `${strParam.substr(0, maxLength / 2 - 3)}...${strParam.substr(\n        strParam.length - maxLength / 2,\n        strParam.length\n      )}`;\n    }\n\n    return strParam;\n  },\n\n  /**\n   * Pads a string with a specified character to reach a target length.\n   * @param str - The string or number to pad\n   * @param length - The target length after padding\n   * @param char - The character to use for padding\n   * @param right - Whether to pad on the right side (default: false, pads left)\n   * @returns The padded string\n   * @example\n   * ```typescript\n   * StringUtils.pad('5', 3, '0'); // Returns \"005\"\n   * StringUtils.pad('hello', 8, '*', true); // Returns \"hello***\"\n   * ```\n   */\n  pad: (\n    str: string | number,\n    length: number,\n    char: string,\n    right = false\n  ): string => {\n    if ((!str && str !== 0) || !length || !char) return String(str);\n\n    const pad = new Array(length + 1).join(char);\n    return right\n      ? String(str) + pad.substring(0, pad.length - String(str).length)\n      : pad.substring(0, pad.length - String(str).length) + String(str);\n  },\n\n  /**\n   * Replaces all occurrences of a substring in a string.\n   * @param str - The string to modify\n   * @param find - The substring to find and replace\n   * @param replace - The substring to replace with\n   * @returns The modified string with all occurrences replaced\n   * @example\n   * ```typescript\n   * StringUtils.replaceAll('hello world hello', 'hello', 'hi'); // Returns \"hi world hi\"\n   * StringUtils.replaceAll('foo-bar-baz', '-', '_'); // Returns \"foo_bar_baz\"\n   * ```\n   */\n  replaceAll: (str: string, find: string, replace: string): string => {\n    if (!str) return str;\n    const re = new RegExp(find, \"g\");\n    return str.replace(re, replace);\n  },\n\n  /**\n   * Sorts two values as strings with specified direction.\n   * @param val1 - The first value to compare\n   * @param val2 - The second value to compare\n   * @param direction - The sort direction: 'asc' for ascending, 'desc' for descending (default: 'asc')\n   * @returns A number indicating the sort order (-1, 0, or 1)\n   * @example\n   * ```typescript\n   * StringUtils.sort('apple', 'banana'); // Returns -1 (apple comes before banana)\n   * StringUtils.sort('zebra', 'apple', 'desc'); // Returns -1 (zebra comes before apple in desc order)\n   * ```\n   */\n  sort: (\n    val1: unknown,\n    val2: unknown,\n    direction: \"asc\" | \"desc\" = \"asc\"\n  ): number => {\n    const [a, b] = direction === \"asc\" ? [val1, val2] : [val2, val1];\n    if (!(a && b)) return 0;\n    return StringUtils.toString(a).localeCompare(StringUtils.toString(b));\n  },\n\n  /**\n   * Sorts two values as strings in ascending order.\n   * @param val1 - The first value to compare\n   * @param val2 - The second value to compare\n   * @returns A number indicating the sort order (-1, 0, or 1)\n   * @example\n   * ```typescript\n   * StringUtils.sortAsc('banana', 'apple'); // Returns 1\n   * ```\n   */\n  sortAsc: (val1: unknown, val2: unknown): number => {\n    return StringUtils.sort(val1, val2);\n  },\n\n  /**\n   * Sorts two values as strings in descending order.\n   * @param val1 - The first value to compare\n   * @param val2 - The second value to compare\n   * @returns A number indicating the sort order (-1, 0, or 1)\n   * @example\n   * ```typescript\n   * StringUtils.sortDesc('apple', 'banana'); // Returns 1\n   * ```\n   */\n  sortDesc: (val1: unknown, val2: unknown): number => {\n    return StringUtils.sort(val1, val2, \"desc\");\n  },\n\n  /**\n   * Converts a value to lowercase string.\n   * @param val - The value to convert to lowercase\n   * @returns The lowercase string representation, or empty string if not a string\n   * @example\n   * ```typescript\n   * StringUtils.toLowerCase('HELLO WORLD'); // Returns \"hello world\"\n   * StringUtils.toLowerCase('MixedCase'); // Returns \"mixedcase\"\n   * StringUtils.toLowerCase(123); // Returns \"\"\n   * ```\n   */\n  toLowerCase: (val: unknown): string => {\n    return typeof val === \"string\" ? val.toLowerCase() : \"\";\n  },\n\n  /**\n   * Extracts only numeric characters from a string.\n   * @param val - The string to extract numbers from\n   * @returns A string containing only the numeric characters\n   * @example\n   * ```typescript\n   * StringUtils.toNumbers('abc123def456'); // Returns \"123456\"\n   * StringUtils.toNumbers('phone: (555) 123-4567'); // Returns \"5551234567\"\n   * StringUtils.toNumbers('no numbers here'); // Returns \"\"\n   * ```\n   */\n  toNumbers: (val: unknown): string => {\n    if (!val || !StringUtils.isString(val)) return \"\";\n    return val.replace(/[^\\d]/g, \"\");\n  },\n\n  /**\n   * Converts any value to its string representation.\n   * @param val - The value to convert to string\n   * @returns The string representation of the value\n   * @example\n   * ```typescript\n   * StringUtils.toString(123); // Returns \"123\"\n   * StringUtils.toString(true); // Returns \"true\"\n   * StringUtils.toString(null); // Returns \"null\"\n   * ```\n   */\n  toString: (val: unknown): string => {\n    return String(val);\n  },\n\n  /**\n   * Truncates a string with ellipsis if it exceeds the maximum length.\n   * @param str - The string to truncate\n   * @param maxLength - The maximum length before truncation (default: 100)\n   * @returns The truncated string with ellipsis appended if needed\n   * @example\n   * ```typescript\n   * StringUtils.truncateWithEllipsis('This is a very long string', 10); // Returns \"This is...\"\n   * StringUtils.truncateWithEllipsis('Short', 10); // Returns \"Short\"\n   * ```\n   */\n  truncateWithEllipsis: (str: string, maxLength = 100): string => {\n    if (!str) {\n      return \"\";\n    }\n\n    if (str.length > maxLength) {\n      return `${str.substring(0, maxLength - 3)}...`;\n    }\n\n    return str;\n  },\n\n  /**\n   * Converts the first letter of a string to lowercase.\n   * @param str - The string to convert\n   * @returns The string with the first letter in lowercase\n   * @example\n   * ```typescript\n   * StringUtils.uncapitalize('Hello World'); // Returns \"hello World\"\n   * StringUtils.uncapitalize('UPPERCASE'); // Returns \"uPPERCASE\"\n   * ```\n   */\n  uncapitalize: (str: string): string => {\n    if (!StringUtils.isString(str)) {\n      return \"\";\n    }\n    return str.charAt(0).toLowerCase() + str.slice(1);\n  },\n};\n"],"names":[],"mappings":"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"}