@gzl10/ts-helpers 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/CHANGELOG.md +320 -0
  2. package/README.md +233 -0
  3. package/USAGE-GUIDE.md +800 -0
  4. package/dist/browser/async.js +15 -0
  5. package/dist/browser/async.js.map +1 -0
  6. package/dist/browser/chunk-4O7ZPIJN.js +383 -0
  7. package/dist/browser/chunk-4O7ZPIJN.js.map +1 -0
  8. package/dist/browser/chunk-75XNTC34.js +60 -0
  9. package/dist/browser/chunk-75XNTC34.js.map +1 -0
  10. package/dist/browser/chunk-C3D7YZVE.js +299 -0
  11. package/dist/browser/chunk-C3D7YZVE.js.map +1 -0
  12. package/dist/browser/chunk-CZL6C2EI.js +452 -0
  13. package/dist/browser/chunk-CZL6C2EI.js.map +1 -0
  14. package/dist/browser/chunk-D4FZFIVA.js +240 -0
  15. package/dist/browser/chunk-D4FZFIVA.js.map +1 -0
  16. package/dist/browser/chunk-IL7NG7IC.js +72 -0
  17. package/dist/browser/chunk-IL7NG7IC.js.map +1 -0
  18. package/dist/browser/chunk-NSBPE2FW.js +17 -0
  19. package/dist/browser/chunk-NSBPE2FW.js.map +1 -0
  20. package/dist/browser/chunk-SLQVNPTH.js +27 -0
  21. package/dist/browser/chunk-SLQVNPTH.js.map +1 -0
  22. package/dist/browser/chunk-WG7ILCUB.js +195 -0
  23. package/dist/browser/chunk-WG7ILCUB.js.map +1 -0
  24. package/dist/browser/chunk-WJA4JDMZ.js +278 -0
  25. package/dist/browser/chunk-WJA4JDMZ.js.map +1 -0
  26. package/dist/browser/chunk-ZFVYLUTT.js +65 -0
  27. package/dist/browser/chunk-ZFVYLUTT.js.map +1 -0
  28. package/dist/browser/chunk-ZYTSVMTI.js +263 -0
  29. package/dist/browser/chunk-ZYTSVMTI.js.map +1 -0
  30. package/dist/browser/dates.js +78 -0
  31. package/dist/browser/dates.js.map +1 -0
  32. package/dist/browser/environment-detection.js +21 -0
  33. package/dist/browser/environment-detection.js.map +1 -0
  34. package/dist/browser/environment.js +34 -0
  35. package/dist/browser/environment.js.map +1 -0
  36. package/dist/browser/errors.js +18 -0
  37. package/dist/browser/errors.js.map +1 -0
  38. package/dist/browser/index.js +412 -0
  39. package/dist/browser/index.js.map +1 -0
  40. package/dist/browser/math.js +51 -0
  41. package/dist/browser/math.js.map +1 -0
  42. package/dist/browser/number.js +10 -0
  43. package/dist/browser/number.js.map +1 -0
  44. package/dist/browser/objects.js +31 -0
  45. package/dist/browser/objects.js.map +1 -0
  46. package/dist/browser/strings.js +80 -0
  47. package/dist/browser/strings.js.map +1 -0
  48. package/dist/browser/validation-core.js +54 -0
  49. package/dist/browser/validation-core.js.map +1 -0
  50. package/dist/browser/validation-crypto.js +28 -0
  51. package/dist/browser/validation-crypto.js.map +1 -0
  52. package/dist/browser/validators.js +98 -0
  53. package/dist/browser/validators.js.map +1 -0
  54. package/dist/cjs/async.js +86 -0
  55. package/dist/cjs/async.js.map +1 -0
  56. package/dist/cjs/dates.js +285 -0
  57. package/dist/cjs/dates.js.map +1 -0
  58. package/dist/cjs/environment-detection.js +84 -0
  59. package/dist/cjs/environment-detection.js.map +1 -0
  60. package/dist/cjs/environment.js +261 -0
  61. package/dist/cjs/environment.js.map +1 -0
  62. package/dist/cjs/errors.js +80 -0
  63. package/dist/cjs/errors.js.map +1 -0
  64. package/dist/cjs/index.js +2035 -0
  65. package/dist/cjs/index.js.map +1 -0
  66. package/dist/cjs/math.js +388 -0
  67. package/dist/cjs/math.js.map +1 -0
  68. package/dist/cjs/number.js +37 -0
  69. package/dist/cjs/number.js.map +1 -0
  70. package/dist/cjs/objects.js +249 -0
  71. package/dist/cjs/objects.js.map +1 -0
  72. package/dist/cjs/strings.js +253 -0
  73. package/dist/cjs/strings.js.map +1 -0
  74. package/dist/cjs/validation.js +450 -0
  75. package/dist/cjs/validation.js.map +1 -0
  76. package/dist/esm/async.js +15 -0
  77. package/dist/esm/async.js.map +1 -0
  78. package/dist/esm/chunk-4O7ZPIJN.js +383 -0
  79. package/dist/esm/chunk-4O7ZPIJN.js.map +1 -0
  80. package/dist/esm/chunk-75XNTC34.js +60 -0
  81. package/dist/esm/chunk-75XNTC34.js.map +1 -0
  82. package/dist/esm/chunk-BDOBKBKA.js +72 -0
  83. package/dist/esm/chunk-BDOBKBKA.js.map +1 -0
  84. package/dist/esm/chunk-C3D7YZVE.js +299 -0
  85. package/dist/esm/chunk-C3D7YZVE.js.map +1 -0
  86. package/dist/esm/chunk-CZL6C2EI.js +452 -0
  87. package/dist/esm/chunk-CZL6C2EI.js.map +1 -0
  88. package/dist/esm/chunk-EBLSTOEC.js +263 -0
  89. package/dist/esm/chunk-EBLSTOEC.js.map +1 -0
  90. package/dist/esm/chunk-NSBPE2FW.js +17 -0
  91. package/dist/esm/chunk-NSBPE2FW.js.map +1 -0
  92. package/dist/esm/chunk-SLQVNPTH.js +27 -0
  93. package/dist/esm/chunk-SLQVNPTH.js.map +1 -0
  94. package/dist/esm/chunk-WG7ILCUB.js +195 -0
  95. package/dist/esm/chunk-WG7ILCUB.js.map +1 -0
  96. package/dist/esm/chunk-WJA4JDMZ.js +278 -0
  97. package/dist/esm/chunk-WJA4JDMZ.js.map +1 -0
  98. package/dist/esm/chunk-ZFVYLUTT.js +65 -0
  99. package/dist/esm/chunk-ZFVYLUTT.js.map +1 -0
  100. package/dist/esm/dates.js +78 -0
  101. package/dist/esm/dates.js.map +1 -0
  102. package/dist/esm/environment-detection.js +21 -0
  103. package/dist/esm/environment-detection.js.map +1 -0
  104. package/dist/esm/environment.js +34 -0
  105. package/dist/esm/environment.js.map +1 -0
  106. package/dist/esm/errors.js +18 -0
  107. package/dist/esm/errors.js.map +1 -0
  108. package/dist/esm/index.js +380 -0
  109. package/dist/esm/index.js.map +1 -0
  110. package/dist/esm/math.js +51 -0
  111. package/dist/esm/math.js.map +1 -0
  112. package/dist/esm/number.js +10 -0
  113. package/dist/esm/number.js.map +1 -0
  114. package/dist/esm/objects.js +31 -0
  115. package/dist/esm/objects.js.map +1 -0
  116. package/dist/esm/strings.js +80 -0
  117. package/dist/esm/strings.js.map +1 -0
  118. package/dist/esm/validation.js +54 -0
  119. package/dist/esm/validation.js.map +1 -0
  120. package/dist/node/async.js +93 -0
  121. package/dist/node/async.js.map +1 -0
  122. package/dist/node/csv.js +102 -0
  123. package/dist/node/csv.js.map +1 -0
  124. package/dist/node/data.js +880 -0
  125. package/dist/node/data.js.map +1 -0
  126. package/dist/node/dates.js +324 -0
  127. package/dist/node/dates.js.map +1 -0
  128. package/dist/node/environment.js +278 -0
  129. package/dist/node/environment.js.map +1 -0
  130. package/dist/node/errors.js +89 -0
  131. package/dist/node/errors.js.map +1 -0
  132. package/dist/node/index.js +3151 -0
  133. package/dist/node/index.js.map +1 -0
  134. package/dist/node/json.js +107 -0
  135. package/dist/node/json.js.map +1 -0
  136. package/dist/node/math.js +413 -0
  137. package/dist/node/math.js.map +1 -0
  138. package/dist/node/number.js +42 -0
  139. package/dist/node/number.js.map +1 -0
  140. package/dist/node/objects.js +264 -0
  141. package/dist/node/objects.js.map +1 -0
  142. package/dist/node/strings.js +293 -0
  143. package/dist/node/strings.js.map +1 -0
  144. package/dist/node/tree.js +89 -0
  145. package/dist/node/tree.js.map +1 -0
  146. package/dist/node/validation-core.js +477 -0
  147. package/dist/node/validation-core.js.map +1 -0
  148. package/dist/node/validation-crypto.js +179 -0
  149. package/dist/node/validation-crypto.js.map +1 -0
  150. package/dist/node/validation.js +677 -0
  151. package/dist/node/validation.js.map +1 -0
  152. package/dist/node/validators.js +123 -0
  153. package/dist/node/validators.js.map +1 -0
  154. package/dist/node-esm/async.js +15 -0
  155. package/dist/node-esm/async.js.map +1 -0
  156. package/dist/node-esm/chunk-3YOF7NPT.js +299 -0
  157. package/dist/node-esm/chunk-3YOF7NPT.js.map +1 -0
  158. package/dist/node-esm/chunk-64TBXJQS.js +263 -0
  159. package/dist/node-esm/chunk-64TBXJQS.js.map +1 -0
  160. package/dist/node-esm/chunk-75XNTC34.js +60 -0
  161. package/dist/node-esm/chunk-75XNTC34.js.map +1 -0
  162. package/dist/node-esm/chunk-C4PKXIPB.js +278 -0
  163. package/dist/node-esm/chunk-C4PKXIPB.js.map +1 -0
  164. package/dist/node-esm/chunk-CMDFZME3.js +452 -0
  165. package/dist/node-esm/chunk-CMDFZME3.js.map +1 -0
  166. package/dist/node-esm/chunk-DZZPUYMP.js +74 -0
  167. package/dist/node-esm/chunk-DZZPUYMP.js.map +1 -0
  168. package/dist/node-esm/chunk-HTSEHRHI.js +195 -0
  169. package/dist/node-esm/chunk-HTSEHRHI.js.map +1 -0
  170. package/dist/node-esm/chunk-JCAUVOPH.js +27 -0
  171. package/dist/node-esm/chunk-JCAUVOPH.js.map +1 -0
  172. package/dist/node-esm/chunk-KBHE3K2F.js +505 -0
  173. package/dist/node-esm/chunk-KBHE3K2F.js.map +1 -0
  174. package/dist/node-esm/chunk-LYTET5NX.js +65 -0
  175. package/dist/node-esm/chunk-LYTET5NX.js.map +1 -0
  176. package/dist/node-esm/chunk-PZ5AY32C.js +10 -0
  177. package/dist/node-esm/chunk-PZ5AY32C.js.map +1 -0
  178. package/dist/node-esm/chunk-UKGXL2QO.js +383 -0
  179. package/dist/node-esm/chunk-UKGXL2QO.js.map +1 -0
  180. package/dist/node-esm/chunk-XAEYT23H.js +164 -0
  181. package/dist/node-esm/chunk-XAEYT23H.js.map +1 -0
  182. package/dist/node-esm/csv.js +63 -0
  183. package/dist/node-esm/csv.js.map +1 -0
  184. package/dist/node-esm/data.js +32 -0
  185. package/dist/node-esm/data.js.map +1 -0
  186. package/dist/node-esm/dates.js +78 -0
  187. package/dist/node-esm/dates.js.map +1 -0
  188. package/dist/node-esm/environment.js +34 -0
  189. package/dist/node-esm/environment.js.map +1 -0
  190. package/dist/node-esm/errors.js +18 -0
  191. package/dist/node-esm/errors.js.map +1 -0
  192. package/dist/node-esm/index.js +426 -0
  193. package/dist/node-esm/index.js.map +1 -0
  194. package/dist/node-esm/json.js +68 -0
  195. package/dist/node-esm/json.js.map +1 -0
  196. package/dist/node-esm/math.js +51 -0
  197. package/dist/node-esm/math.js.map +1 -0
  198. package/dist/node-esm/number.js +10 -0
  199. package/dist/node-esm/number.js.map +1 -0
  200. package/dist/node-esm/objects.js +31 -0
  201. package/dist/node-esm/objects.js.map +1 -0
  202. package/dist/node-esm/strings.js +80 -0
  203. package/dist/node-esm/strings.js.map +1 -0
  204. package/dist/node-esm/tree.js +8 -0
  205. package/dist/node-esm/tree.js.map +1 -0
  206. package/dist/node-esm/validation-core.js +54 -0
  207. package/dist/node-esm/validation-core.js.map +1 -0
  208. package/dist/node-esm/validation-crypto.js +26 -0
  209. package/dist/node-esm/validation-crypto.js.map +1 -0
  210. package/dist/node-esm/validation.js +606 -0
  211. package/dist/node-esm/validation.js.map +1 -0
  212. package/dist/node-esm/validators.js +98 -0
  213. package/dist/node-esm/validators.js.map +1 -0
  214. package/dist/types/async-C8gvbSG-.d.ts +453 -0
  215. package/dist/types/async.d.ts +1 -0
  216. package/dist/types/csv.d.ts +226 -0
  217. package/dist/types/data.d.ts +1561 -0
  218. package/dist/types/dates-hTiE0Z11.d.ts +298 -0
  219. package/dist/types/dates.d.ts +1 -0
  220. package/dist/types/environment-B8eLS7KT.d.ts +420 -0
  221. package/dist/types/environment-detection.d.ts +102 -0
  222. package/dist/types/environment.d.ts +1 -0
  223. package/dist/types/errors.d.ts +147 -0
  224. package/dist/types/index.d.ts +211 -0
  225. package/dist/types/json.d.ts +284 -0
  226. package/dist/types/math-BQ9Lwdp7.d.ts +2060 -0
  227. package/dist/types/math.d.ts +1 -0
  228. package/dist/types/number-CYnQfLWj.d.ts +44 -0
  229. package/dist/types/number.d.ts +1 -0
  230. package/dist/types/objects-BohS8GCS.d.ts +1185 -0
  231. package/dist/types/objects.d.ts +1 -0
  232. package/dist/types/strings-CiqRPYLL.d.ts +1349 -0
  233. package/dist/types/strings.d.ts +1 -0
  234. package/dist/types/tree.d.ts +284 -0
  235. package/dist/types/validation-core-DfHF8rCG.d.ts +238 -0
  236. package/dist/types/validation-crypto-browser.d.ts +56 -0
  237. package/dist/types/validation-crypto-node.d.ts +31 -0
  238. package/dist/types/validation.d.ts +1 -0
  239. package/dist/types/validators.d.ts +216 -0
  240. package/package.json +253 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/universal/index.ts","../../src/universal/validation-core.ts","../../src/universal/environment-detection.ts","../../src/environment.ts","../../src/strings.ts","../../src/objects.ts","../../src/dates.ts","../../src/math.ts","../../src/number.ts","../../src/async.ts","../../src/errors.ts"],"sourcesContent":["/**\n * Universal exports - Safe for all environments\n * No crypto dependencies - browser and Node.js compatible\n */\n\n// Import universal modules (safe for all environments)\nimport * as validationCore from './validation-core'\nimport * as environmentDetection from './environment-detection'\nimport * as stringFunctions from '../strings'\nimport * as objectFunctions from '../objects'\nimport * as dateFunctions from '../dates'\nimport * as mathFunctions from '../math'\nimport * as asyncFunctions from '../async'\nimport * as environmentModule from '../environment'\nimport * as numberModule from '../number'\n\n// NOTE: data, csv, json, tree modules are NOT included in universal build\n// because they have Node.js dependencies (fs/promises, path)\n// These are available in Node.js specific builds\n\n// Create flat API object - universal functions only (safe for browser)\nconst g = {\n // Core validation functions (no crypto)\n ...validationCore,\n\n // String functions\n ...stringFunctions,\n\n // Object/Array functions\n ...objectFunctions,\n\n // Date functions\n ...dateFunctions,\n\n // Math functions\n ...mathFunctions,\n\n // Async functions\n ...asyncFunctions,\n\n // Number utilities\n ...numberModule,\n\n // Environment utilities (original)\n ...environmentModule,\n\n // Enhanced environment detection\n ...environmentDetection,\n}\n\n// Export both default and named exports\nexport default g\n\n// Named exports for specific imports\nexport {\n validationCore as validation,\n stringFunctions as strings,\n objectFunctions as objects,\n dateFunctions as dates,\n mathFunctions as math,\n asyncFunctions as async,\n environmentModule as environment,\n numberModule as number,\n}\n\n// Re-export individual functions for tree-shaking\nexport * from './validation-core'\nexport * from './environment-detection'\nexport * from '../strings'\nexport * from '../objects'\nexport * from '../dates'\nexport * from '../math'\nexport * from '../async'\nexport * from '../environment'\nexport * from '../number'\n","/**\n * Core validation utilities - Universal (Browser + Node.js compatible)\n * NO crypto dependencies - safe for all environments\n */\n\nimport validator from 'validator'\n\n// =============================================================================\n// RANDOM GENERATORS (crypto-free)\n// =============================================================================\n\nconst randomInteger = (min: number, max: number): number => {\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\nconst randomString = (length: number, pool?: string): string => {\n const chars = pool || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n let result = ''\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length))\n }\n return result\n}\n\nconst randomAlphaString = (length: number, casing?: 'upper' | 'lower'): string => {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\n let result = randomString(length, chars)\n if (casing === 'upper') result = result.toUpperCase()\n if (casing === 'lower') result = result.toLowerCase()\n return result\n}\n\nconst randomAlphaNumericString = (length: number, casing?: 'upper' | 'lower'): string => {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n let result = randomString(length, chars)\n if (casing === 'upper') result = result.toUpperCase()\n if (casing === 'lower') result = result.toLowerCase()\n return result\n}\n\nconst pickone = <T>(array: T[]): T => {\n return array[Math.floor(Math.random() * array.length)]\n}\n\nconst randomBool = (likelihood = 50): boolean => {\n return Math.random() * 100 < likelihood\n}\n\n// =============================================================================\n// GENERATORS - Random data generators (crypto-free)\n// =============================================================================\n\n/**\n * Generates a random integer between min and max (inclusive)\n * @param min - Minimum value (default: 0)\n * @param max - Maximum value (default: 100)\n * @returns Random integer between min and max\n * @example\n * ```ts\n * const dice = generateRandomInteger(1, 6) // 1, 2, 3, 4, 5, or 6\n * const percent = generateRandomInteger(0, 100) // 0 to 100\n * const id = generateRandomInteger(1000, 9999) // 4-digit ID\n * ```\n */\nexport const generateRandomInteger = (min = 0, max = 100): number => {\n return randomInteger(min, max)\n}\n\n/**\n * Generates a random alphabetic string (letters only)\n * @param options - Configuration object\n * @param options.length - Length of the string (default: 10)\n * @param options.casing - Case transformation: 'upper', 'lower', or undefined\n * @returns Random alphabetic string\n * @example\n * ```ts\n * const name = generateAlphaString({ length: 8 }) // \"AbCdEfGh\"\n * const upper = generateAlphaString({ length: 5, casing: 'upper' }) // \"ABCDE\"\n * const lower = generateAlphaString({ length: 3, casing: 'lower' }) // \"abc\"\n * ```\n */\nexport const generateAlphaString = (\n options: { length?: number; casing?: 'upper' | 'lower' | undefined } = {}\n): string => {\n const { length = 10, casing = undefined } = options\n return randomAlphaString(length, casing)\n}\n\n/**\n * Generates a random alphanumeric string (letters and numbers)\n * @param options - Configuration object\n * @param options.length - Length of the string (default: 10)\n * @param options.casing - Case transformation: 'upper', 'lower', or undefined\n * @returns Random alphanumeric string\n * @example\n * ```ts\n * const token = generateAlphaNumericString({ length: 12 }) // \"aB3cD4eF5gH6\"\n * const code = generateAlphaNumericString({ length: 6, casing: 'upper' }) // \"A1B2C3\"\n * const key = generateAlphaNumericString({ length: 8, casing: 'lower' }) // \"a1b2c3d4\"\n * ```\n */\nexport const generateAlphaNumericString = (\n options: { length?: number; casing?: 'upper' | 'lower' | undefined } = {}\n): string => {\n const { length = 10, casing = undefined } = options\n return randomAlphaNumericString(length, casing)\n}\n\n/**\n * Generates a random complex string with all characters (letters, numbers, symbols)\n * @param options - Configuration object\n * @param options.length - Length of the string (default: 10)\n * @param options.casing - Case transformation (currently not applied to symbols)\n * @returns Random complex string\n * @example\n * ```ts\n * const password = generateComplexString({ length: 16 }) // \"aB3#cD4$eF5%gH6\"\n * const secret = generateComplexString({ length: 32 }) // Complex 32-char string\n * const temp = generateComplexString() // 10 characters by default\n * ```\n */\nexport const generateComplexString = (\n options: { length?: number; casing?: 'upper' | 'lower' | undefined } = {}\n): string => {\n const { length = 10, casing: _casing = undefined } = options\n return randomString(length)\n}\n\n/**\n * Generates a username from an email address\n * @param email - Email address to extract username from\n * @param randomDigits - Number of random digits to append (default: 1)\n * @returns Username derived from email with random suffix\n * @example\n * ```ts\n * const user1 = generateUsernameFromEmail('john.doe@example.com', 2) // \"johndoe47\"\n * const user2 = generateUsernameFromEmail('maria-garcia@test.org', 3) // \"mariagarcia823\"\n * const fallback = generateUsernameFromEmail('invalid-email', 2) // \"user42\"\n * ```\n */\nexport const generateUsernameFromEmail = (email: string, randomDigits = 1): string => {\n if (!email || !email.includes('@'))\n return `user${Math.floor(Math.random() * Math.pow(10, randomDigits))}`\n\n const localPart = email.split('@')[0]\n const username = localPart\n .toLowerCase()\n .replace(/[^a-z0-9]/g, '')\n .substring(0, 12)\n\n const randomSuffix = Math.floor(Math.random() * Math.pow(10, randomDigits))\n return username + randomSuffix\n}\n\n/**\n * Generates a random username with adjective + noun pattern\n * @param separator - Character to separate adjective and noun (default: '')\n * @param randomDigits - Number of random digits to append (default: 1)\n * @param length - Maximum length of username (default: 8)\n * @returns Random username like \"coolcat5\" or \"brave_wolf3\"\n * @example\n * ```ts\n * const user1 = generateUsername() // \"coolcat5\"\n * const user2 = generateUsername('_', 2) // \"brave_wolf83\"\n * const user3 = generateUsername('-', 3, 15) // \"smart-eagle247\"\n * ```\n */\nexport const generateUsername = (separator = '', randomDigits = 1, length = 8): string => {\n const adjectives = [\n 'cool',\n 'happy',\n 'smart',\n 'fast',\n 'nice',\n 'wild',\n 'free',\n 'bold',\n 'calm',\n 'brave',\n ]\n const nouns = ['cat', 'dog', 'bird', 'fish', 'lion', 'bear', 'wolf', 'tiger', 'eagle', 'shark']\n\n const adjective = adjectives[Math.floor(Math.random() * adjectives.length)]\n const noun = nouns[Math.floor(Math.random() * nouns.length)]\n const randomSuffix = Math.floor(Math.random() * Math.pow(10, randomDigits))\n\n const username = adjective + separator + noun + randomSuffix\n\n return username.length > length ? username.substring(0, length) : username\n}\n\n// =============================================================================\n// SPANISH GENERATORS\n// =============================================================================\n\n/**\n * Generates a valid Spanish NIF (Número de Identificación Fiscal)\n * @returns A valid NIF string in format '12345678Z'\n * @example\n * ```ts\n * const nif1 = generateSpanishNIF() // \"87654321T\"\n * const nif2 = generateSpanishNIF() // \"12345678Z\"\n *\n * // Verify it's valid\n * const nif = generateSpanishNIF()\n * console.log(validateNIF(nif)) // true\n * ```\n */\nexport const generateSpanishNIF = (): string => {\n const number = randomInteger(10000000, 99999999)\n const letters = 'TRWAGMYFPDXBNJZSQVHLCKE'\n const letter = letters[number % 23]\n return `${number}${letter}`\n}\n\n/**\n * Generates a valid Spanish NIE (Número de Identidad de Extranjero)\n * @returns A valid NIE string in format 'X1234567L'\n * @example\n * ```ts\n * const nie1 = generateSpanishNIE() // \"X1234567L\"\n * const nie2 = generateSpanishNIE() // \"Y9876543R\"\n * const nie3 = generateSpanishNIE() // \"Z2468135T\"\n *\n * // Verify it's valid\n * const nie = generateSpanishNIE()\n * console.log(isValidNIE(nie)) // true\n * ```\n */\nexport const generateSpanishNIE = (): string => {\n const prefixes = ['X', 'Y', 'Z']\n const selectedPrefix = pickone(prefixes)\n const prefixValue = selectedPrefix === 'X' ? 0 : selectedPrefix === 'Y' ? 1 : 2\n const number = randomInteger(1000000, 9999999)\n const letters = 'TRWAGMYFPDXBNJZSQVHLCKE'\n const calculationNumber = prefixValue * 10000000 + number\n const letter = letters[calculationNumber % 23]\n return `${selectedPrefix}${number}${letter}`\n}\n\n/**\n * Generates a valid Spanish CIF (Código de Identificación Fiscal)\n * @returns A valid CIF string in format 'A12345674' or 'B87654321'\n * @example\n * ```ts\n * const cif1 = generateSpanishCIF() // \"A12345674\"\n * const cif2 = generateSpanishCIF() // \"B87654321\"\n * const cif3 = generateSpanishCIF() // \"G28456789\"\n *\n * // Verify it's valid\n * const cif = generateSpanishCIF()\n * console.log(isValidCIF(cif)) // true\n *\n * // Different organization types\n * // A,B,E,H = Sociedades Anónimas/Limitadas\n * // G,U = Fundaciones, asociaciones\n * // N,P,Q,R,S,W = Organismos públicos\n * ```\n */\nexport const generateSpanishCIF = (): string => {\n const organizationTypes = [\n 'A',\n 'B',\n 'C',\n 'D',\n 'E',\n 'F',\n 'G',\n 'H',\n 'J',\n 'N',\n 'P',\n 'Q',\n 'R',\n 'S',\n 'U',\n 'V',\n 'W',\n ]\n const organizationType = pickone(organizationTypes)\n const number = randomInteger(1000000, 9999999).toString().padStart(7, '0')\n\n // Calculate control digit\n let sum = 0\n for (let i = 0; i < 7; i++) {\n let digit = parseInt(number[i])\n if (i % 2 === 0) {\n digit *= 2\n if (digit > 9) digit = Math.floor(digit / 10) + (digit % 10)\n }\n sum += digit\n }\n\n const controlDigit = (10 - (sum % 10)) % 10\n const controlLetter = 'JABCDEFGHI'[controlDigit]\n const control = ['N', 'P', 'Q', 'R', 'S', 'W'].includes(organizationType)\n ? controlLetter\n : randomBool()\n ? controlDigit.toString()\n : controlLetter\n\n return `${organizationType}${number}${control}`\n}\n\nexport const generateSpanishPostalCode = (): string => {\n const validPrefixes = [\n '01',\n '02',\n '03',\n '04',\n '05',\n '06',\n '07',\n '08',\n '09',\n '10',\n '11',\n '12',\n '13',\n '14',\n '15',\n '16',\n '17',\n '18',\n '19',\n '20',\n '21',\n '22',\n '23',\n '24',\n '25',\n '26',\n '27',\n '28',\n '29',\n '30',\n '31',\n '32',\n '33',\n '34',\n '35',\n '36',\n '37',\n '38',\n '39',\n '40',\n '41',\n '42',\n '43',\n '44',\n '45',\n '46',\n '47',\n '48',\n '49',\n '50',\n '51',\n '52',\n ]\n\n const firstDigit = pickone(validPrefixes)\n const remainingDigits = randomString(3, '0123456789')\n return `${firstDigit}${remainingDigits}`\n}\n\nexport const generateSpanishIBAN = (): string => {\n const bankCode = randomString(4, '0123456789')\n const branchCode = randomString(4, '0123456789')\n const controlDigits = randomString(2, '0123456789')\n const accountNumber = randomString(10, '0123456789')\n\n // Calculate IBAN check digits\n const accountPart = `${bankCode}${branchCode}${controlDigits}${accountNumber}`\n const rearranged = `${accountPart}142800`\n\n // Calculate mod 97\n const checkDigits = String(98n - (BigInt(rearranged) % 97n)).padStart(2, '0')\n\n return `ES${checkDigits}${bankCode}${branchCode}${controlDigits}${accountNumber}`\n}\n\n// =============================================================================\n// GENERAL GENERATORS\n// =============================================================================\n\nexport const generateEmail = (domain?: string): string => {\n const firstNames = [\n 'Ana',\n 'Carlos',\n 'María',\n 'José',\n 'Laura',\n 'David',\n 'Carmen',\n 'Antonio',\n 'Isabel',\n 'Manuel',\n ]\n const lastNames = [\n 'García',\n 'González',\n 'López',\n 'Martínez',\n 'Sánchez',\n 'Pérez',\n 'Gómez',\n 'Martín',\n 'Jiménez',\n 'Ruiz',\n ]\n const domains = ['gmail.com', 'hotmail.com', 'yahoo.es', 'outlook.com', 'test.com']\n\n const firstName = pickone(firstNames)\n const lastName = pickone(lastNames)\n const emailDomain = domain || pickone(domains)\n\n const formats = [\n `${firstName.toLowerCase()}.${lastName.toLowerCase()}@${emailDomain}`,\n `${firstName.toLowerCase()}${randomInteger(1, 99)}@${emailDomain}`,\n `${firstName.toLowerCase()}.${lastName.toLowerCase()}${randomInteger(1, 9)}@${emailDomain}`,\n `${firstName.toLowerCase()}${lastName.toLowerCase()}@${emailDomain}`,\n ]\n\n const username = pickone(formats)\n return username.toLowerCase()\n}\n\nexport const generatePassword = (\n options: {\n length?: number\n includeUppercase?: boolean\n includeLowercase?: boolean\n includeNumbers?: boolean\n includeSymbols?: boolean\n } = {}\n): string => {\n const {\n length = 12,\n includeUppercase = true,\n includeLowercase = true,\n includeNumbers = true,\n includeSymbols = true,\n } = options\n\n const minLength = 4\n const maxLength = 30\n const targetLength = length || randomInteger(minLength, maxLength)\n\n const upperChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n const lowerChars = 'abcdefghijklmnopqrstuvwxyz'\n const numberChars = '0123456789'\n const symbolChars = '!@#$%^&*()_+-=[]{}|;:,.<>?'\n\n let charset = ''\n let requiredChars = ''\n\n if (includeUppercase) {\n charset += upperChars\n requiredChars += upperChars.charAt(Math.floor(Math.random() * upperChars.length))\n }\n if (includeLowercase) {\n charset += lowerChars\n requiredChars += lowerChars.charAt(Math.floor(Math.random() * lowerChars.length))\n }\n if (includeNumbers) {\n charset += numberChars\n requiredChars += numberChars.charAt(Math.floor(Math.random() * numberChars.length))\n }\n if (includeSymbols) {\n charset += symbolChars\n requiredChars += symbolChars.charAt(Math.floor(Math.random() * symbolChars.length))\n }\n\n if (!charset) charset = 'abcdefghijklmnopqrstuvwxyz'\n\n let password = requiredChars\n const remainingLength = targetLength - requiredChars.length\n\n for (let i = 0; i < remainingLength; i++) {\n password += charset.charAt(Math.floor(Math.random() * charset.length))\n }\n\n return password\n .split('')\n .sort(() => Math.random() - 0.5)\n .join('')\n}\n\nexport const generateHexColor = (shortFormat?: boolean): string => {\n const hexChars = '0123456789ABCDEF'\n const useShortFormat = shortFormat !== undefined ? shortFormat : randomBool()\n\n if (useShortFormat) {\n const r = pickone(hexChars.split(''))\n const g = pickone(hexChars.split(''))\n const b = pickone(hexChars.split(''))\n return `#${r}${g}${b}`\n } else {\n const color = randomString(6, hexChars)\n return `#${color}`\n }\n}\n\n// =============================================================================\n// VALIDATORS\n// =============================================================================\n\n/**\n * Validates a Spanish NIF (Número de Identificación Fiscal)\n * @param nif - The NIF string to validate\n * @returns true if the NIF is valid, false otherwise\n * @example\n * ```ts\n * console.log(isValidNIF('12345678Z')) // true\n * console.log(isValidNIF('87654321T')) // true\n * console.log(isValidNIF('12345678A')) // false (wrong letter)\n * console.log(isValidNIF('1234567Z')) // false (wrong length)\n * console.log(isValidNIF('')) // false (empty)\n *\n * // Case insensitive and handles whitespace\n * console.log(isValidNIF(' 12345678z ')) // true\n * ```\n */\nexport const isValidNIF = (nif: string): boolean => {\n if (!nif || typeof nif !== 'string') return false\n\n const cleanNif = nif.trim().toUpperCase()\n const nifRegex = /^[0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKE]$/\n\n if (!nifRegex.test(cleanNif)) return false\n\n const number = parseInt(cleanNif.substring(0, 8))\n const letter = cleanNif.charAt(8)\n const letters = 'TRWAGMYFPDXBNJZSQVHLCKE'\n const expectedLetter = letters[number % 23]\n\n return letter === expectedLetter\n}\n\n/**\n * Alias for isValidNIF - validates a Spanish NIF\n * @param nif - The NIF string to validate\n * @returns true if the NIF is valid, false otherwise\n * @example\n * ```ts\n * console.log(validateNIF('12345678Z')) // true\n * // Same functionality as isValidNIF\n * ```\n */\nexport const validateNIF = isValidNIF\n\n/**\n * Validates a Spanish NIE (Número de Identidad de Extranjero)\n * @param nie - The NIE string to validate\n * @returns true if the NIE is valid, false otherwise\n * @example\n * ```ts\n * console.log(isValidNIE('X1234567L')) // true\n * console.log(isValidNIE('Y9876543R')) // true\n * console.log(isValidNIE('Z2468135T')) // true\n * console.log(isValidNIE('X1234567A')) // false (wrong letter)\n * console.log(isValidNIE('W1234567L')) // false (invalid prefix)\n * console.log(isValidNIE('X123456L')) // false (wrong length)\n *\n * // Case insensitive and handles whitespace\n * console.log(isValidNIE(' x1234567l ')) // true\n * ```\n */\nexport const isValidNIE = (nie: string): boolean => {\n if (!nie || typeof nie !== 'string') return false\n\n const cleanNie = nie.trim().toUpperCase()\n const nieRegex = /^[XYZ][0-9]{7}[TRWAGMYFPDXBNJZSQVHLCKE]$/\n\n if (!nieRegex.test(cleanNie)) return false\n\n const prefix = cleanNie.charAt(0)\n const number = parseInt(cleanNie.substring(1, 8))\n const letter = cleanNie.charAt(8)\n\n const prefixValue = prefix === 'X' ? 0 : prefix === 'Y' ? 1 : 2\n const calculationNumber = prefixValue * 10000000 + number\n const letters = 'TRWAGMYFPDXBNJZSQVHLCKE'\n const expectedLetter = letters[calculationNumber % 23]\n\n return letter === expectedLetter\n}\n\nexport const isValidCIF = (cif: string): boolean => {\n if (!cif || typeof cif !== 'string') return false\n\n const cleanCif = cif.trim().toUpperCase()\n const cifRegex = /^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$/\n\n if (!cifRegex.test(cleanCif)) return false\n\n const organizationType = cleanCif.charAt(0)\n const number = cleanCif.substring(1, 8)\n const control = cleanCif.charAt(8)\n\n let sum = 0\n for (let i = 0; i < 7; i++) {\n let digit = parseInt(number[i])\n if (i % 2 === 0) {\n digit *= 2\n if (digit > 9) digit = Math.floor(digit / 10) + (digit % 10)\n }\n sum += digit\n }\n\n const controlDigit = (10 - (sum % 10)) % 10\n const controlLetter = 'JABCDEFGHI'[controlDigit]\n\n if (['N', 'P', 'Q', 'R', 'S', 'W'].includes(organizationType)) {\n return control === controlLetter\n } else {\n return control === controlDigit.toString() || control === controlLetter\n }\n}\n\nexport const isValidSpanishPostalCode = (postalCode: string): boolean => {\n if (!postalCode || typeof postalCode !== 'string') return false\n\n const cleanCode = postalCode.trim()\n const postalCodeRegex = /^(0[1-9]|[1-4][0-9]|5[0-2])[0-9]{3}$/\n\n return postalCodeRegex.test(cleanCode)\n}\n\nexport const isValidSpanishPhone = (phone: string): boolean => {\n if (!phone || typeof phone !== 'string') return false\n\n const cleanPhone = phone.replace(/[\\s\\-()]/g, '')\n const phoneRegex = /^(?:\\+34|0034|34)?([679][0-9]{8})$/\n\n return phoneRegex.test(cleanPhone)\n}\n\nexport const isValidEmail = (email: string): boolean => {\n if (!email || typeof email !== 'string') return false\n return validator.isEmail(email)\n}\n\nexport const isValidURL = (url: string): boolean => {\n if (!url || typeof url !== 'string') return false\n\n if (validator.isURL(url, { require_protocol: true })) {\n return true\n }\n\n try {\n const urlObj = new URL(url)\n return urlObj.hostname === 'localhost' || urlObj.hostname === '127.0.0.1'\n } catch {\n return false\n }\n}\n\nexport const isValidJSON = (str: string): boolean => {\n if (!str || typeof str !== 'string') return false\n try {\n JSON.parse(str)\n return true\n } catch {\n return false\n }\n}\n\nexport const isValidSpanishIBAN = (iban: string): boolean => {\n if (!iban || typeof iban !== 'string') return false\n\n const cleanIban = iban.replace(/\\s/g, '').toUpperCase()\n const ibanRegex = /^ES[0-9]{22}$/\n\n if (!ibanRegex.test(cleanIban)) return false\n\n const rearranged = cleanIban.substring(4) + cleanIban.substring(0, 4)\n const numericString = rearranged.replace(/[A-Z]/g, letter => {\n return (letter.charCodeAt(0) - 55).toString()\n })\n\n let remainder = 0\n for (let i = 0; i < numericString.length; i++) {\n remainder = (remainder * 10 + parseInt(numericString[i])) % 97\n }\n\n return remainder === 1\n}\n","/**\n * Universal crypto capabilities detection utilities\n * Safe for all environments with comprehensive fallbacks\n */\n\nimport { isBrowserEnvironment, isNodeEnvironment } from '../environment'\n\n// Global type declarations for Worker environment (avoid importing lib.webworker)\ndeclare const importScripts: any\ndeclare const self: any\n\n/**\n * Enhanced browser environment detection with additional checks\n * @returns true if running in a browser environment\n * @example\n * ```ts\n * if (isBrowserEnv()) {\n * console.log('Running in browser')\n * }\n * ```\n */\nexport const isBrowserEnv = isBrowserEnvironment\n\n/**\n * Enhanced Node.js environment detection with additional checks\n * @returns true if running in Node.js environment\n * @example\n * ```ts\n * if (isNodeEnv()) {\n * console.log('Running in Node.js')\n * }\n * ```\n */\nexport const isNodeEnv = isNodeEnvironment\n\n/**\n * Detects if running in Worker environment (Web Workers, Service Workers)\n * @returns true if running in a Worker context\n * @example\n * ```ts\n * if (isWorkerEnvironment()) {\n * console.log('Running in Web Worker')\n * }\n * ```\n */\nexport const isWorkerEnvironment = (): boolean => {\n try {\n return (\n typeof importScripts === 'function' &&\n typeof self !== 'undefined' &&\n // Check for Worker global scope without importing types\n 'importScripts' in self\n )\n } catch {\n return false\n }\n}\n\n/**\n * Detects if Web Crypto API is available in the current environment\n * @returns true if crypto.getRandomValues and crypto.subtle are available\n * @example\n * ```ts\n * if (isWebCryptoAvailable()) {\n * const array = new Uint8Array(16)\n * crypto.getRandomValues(array)\n * }\n * ```\n */\nexport const isWebCryptoAvailable = (): boolean => {\n try {\n return (\n typeof crypto !== 'undefined' &&\n typeof crypto.getRandomValues === 'function' &&\n typeof crypto.subtle === 'object'\n )\n } catch {\n return false\n }\n}\n\n/**\n * Detects if Node.js crypto module is available\n * @returns true if Node.js crypto module with hash and random functions is available\n * @example\n * ```ts\n * if (isNodeCryptoAvailable()) {\n * const crypto = require('crypto')\n * const hash = crypto.createHash('sha256')\n * }\n * ```\n */\nexport const isNodeCryptoAvailable = (): boolean => {\n try {\n if (!isNodeEnv()) return false\n const crypto = require('crypto')\n return typeof crypto.createHash === 'function' && typeof crypto.randomBytes === 'function'\n } catch {\n return false\n }\n}\n\n/**\n * Gets the current environment type with automatic detection\n * @returns The detected environment type\n * @example\n * ```ts\n * const env = getEnvironmentType()\n * switch (env) {\n * case 'node': console.log('Server-side'); break\n * case 'browser': console.log('Client-side'); break\n * case 'worker': console.log('Worker thread'); break\n * case 'unknown': console.log('Unknown environment'); break\n * }\n * ```\n */\nexport const getEnvironmentType = (): 'node' | 'browser' | 'worker' | 'unknown' => {\n if (isNodeEnv()) return 'node'\n if (isWorkerEnvironment()) return 'worker'\n if (isBrowserEnv()) return 'browser'\n return 'unknown'\n}\n\n/**\n * Gets available crypto capabilities for the current environment\n * @returns Object containing crypto capability information\n * @example\n * ```ts\n * const caps = getCryptoCapabilities()\n * console.log(caps)\n * // {\n * // webCrypto: true,\n * // nodeCrypto: false,\n * // fallbackOnly: false,\n * // environment: 'browser'\n * // }\n * ```\n */\nexport const getCryptoCapabilities = () => {\n return {\n webCrypto: isWebCryptoAvailable(),\n nodeCrypto: isNodeCryptoAvailable(),\n fallbackOnly: !isWebCryptoAvailable() && !isNodeCryptoAvailable(),\n environment: getEnvironmentType(),\n }\n}\n","/**\n * Environment detection utilities for universal browser/Node.js compatibility\n */\n\n/**\n * Detailed criteria used for environment debugging and analysis\n */\nexport interface EnvironmentCriteria {\n /** True if hostname is localhost, 127.0.0.1, ::1, or .localhost/.local domain */\n isLocalhost: boolean\n /** True if hostname is within private IP ranges (10.x, 192.168.x, 172.16-31.x) */\n isPrivateIP: boolean\n /** True if port is in development range (3000-9999) */\n isDevelopmentPort: boolean\n /** True if development tools are detected (Vue DevTools, __DEV__ global) */\n hasDevtools: boolean\n /** Current NODE_ENV value (Node.js only) */\n nodeEnv?: string\n}\n\n/**\n * Complete environment information with platform detection and debugging criteria\n */\nexport interface EnvironmentInfo {\n /** Runtime platform: 'browser', 'node', or 'unknown' */\n platform: 'browser' | 'node' | 'unknown'\n /** Detected environment: 'development', 'production', or 'test' */\n environment: 'development' | 'production' | 'test'\n /** Protocol used (http/https) - from location or request headers */\n protocol?: string\n /** Hostname - from location or request headers */\n hostname?: string\n /** Browser user agent string (browser only) */\n userAgent?: string\n /** Detailed debugging criteria */\n criteria?: EnvironmentCriteria\n}\n\n/**\n * Detects if the current runtime is Node.js environment\n *\n * Checks for the presence of Node.js-specific globals (process, process.versions.node)\n * and absence of browser globals (window).\n *\n * @returns True if running in Node.js, false otherwise\n *\n * @example\n * ```typescript\n * if (isNodeEnvironment()) {\n * // Node.js specific code\n * const fs = require('fs')\n * }\n * ```\n */\nexport function isNodeEnvironment(): boolean {\n return typeof window === 'undefined' && typeof process !== 'undefined' && !!process.versions?.node\n}\n\n/**\n * Detects if the current runtime is a browser environment\n *\n * Checks for the presence of browser-specific globals (window, document).\n * Also handles testing environments that may mock these globals.\n *\n * @returns True if running in browser, false otherwise\n *\n * @example\n * ```typescript\n * if (isBrowserEnvironment()) {\n * // Browser specific code\n * const url = window.location.href\n * }\n * ```\n */\nexport function isBrowserEnvironment(): boolean {\n // Check both global.window (for tests) and window (for actual browser)\n const win = typeof window !== 'undefined' ? window : (global as any).window\n const doc = typeof document !== 'undefined' ? document : (global as any).document\n return typeof win !== 'undefined' && win !== null && typeof doc !== 'undefined' && doc !== null\n}\n\n/**\n * Detects if the application is running in development mode\n *\n * Uses sophisticated detection logic based on multiple criteria:\n * - Node.js: NODE_ENV variable, request headers (for Express), hostname/protocol analysis\n * - Browser: __DEV__ global, development ports (3000-9999), localhost/private IPs, dev tools\n *\n * Handles reverse proxies correctly by checking forwarded headers.\n *\n * @param req - Optional Express request object for server-side detection\n * @returns True if in development mode, false if production\n *\n * @example\n * ```typescript\n * // Node.js - simple check\n * if (isDevelopment()) {\n * console.log('Development mode')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Express - with request context\n * app.get('/api/status', (req, res) => {\n * const isDev = isDevelopment(req)\n * res.json({ environment: isDev ? 'dev' : 'prod' })\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Browser - automatic detection\n * if (isDevelopment()) {\n * // Enable debug logging, dev tools, etc.\n * enableDebugMode()\n * }\n * ```\n */\nexport function isDevelopment(req?: any): boolean {\n if (isNodeEnvironment()) {\n // En Node.js, verificar NODE_ENV primero\n if (process.env.NODE_ENV === 'production') {\n return false\n }\n if (process.env.NODE_ENV === 'development') {\n return true\n }\n\n // Si hay request object (Express), usar lógica de servidor\n if (req) {\n const protocol = detectProtocol(req)\n const hostname = detectHostname(req)\n\n return protocol === 'http' || isLocalhost(hostname) || isPrivateIP(hostname)\n }\n\n // Fallback para Node.js sin request\n // NODE_ENV undefined se asume como development\n return !process.env.NODE_ENV || process.env.NODE_ENV === 'development'\n }\n\n if (isBrowserEnvironment()) {\n // Verificar variable global de desarrollo (webpack/vite)\n if (\n typeof (globalThis as any).__DEV__ !== 'undefined' &&\n (globalThis as any).__DEV__ === true\n ) {\n return true\n }\n\n // Verificar si hay herramientas de desarrollo activas\n if (\n typeof window !== 'undefined' &&\n (window as any).__VUE_DEVTOOLS_GLOBAL_HOOK__ &&\n typeof location !== 'undefined' &&\n isLocalhost(location.hostname)\n ) {\n return true\n }\n\n // Si location no está disponible, considerar como producción\n if (typeof location === 'undefined') {\n return false\n }\n\n const hostname = location.hostname || ''\n const port = parseInt(location.port || '80')\n\n // Criterios basados en hostname y puerto\n const isDevelopmentPort = port >= 3000 && port <= 9999\n\n // Solo considerar HTTP como desarrollo si el hostname también lo indica\n const isHttpDevelopment =\n location.protocol === 'http:' && (isLocalhost(hostname) || isPrivateIP(hostname))\n\n return isLocalhost(hostname) || isPrivateIP(hostname) || isDevelopmentPort || isHttpDevelopment\n }\n\n return false\n}\n\n/**\n * Detects if the application is running in production mode\n *\n * Simple inverse of isDevelopment() with additional NODE_ENV validation for Node.js.\n *\n * @returns True if in production mode, false if development\n *\n * @example\n * ```typescript\n * if (isProduction()) {\n * // Enable performance optimizations\n * enableProductionMode()\n * }\n * ```\n */\nexport function isProduction(): boolean {\n if (isNodeEnvironment()) {\n return process.env.NODE_ENV === 'production'\n }\n\n // Browser: inverso de isDevelopment (que ya excluye test)\n return !isDevelopment()\n}\n\n/**\n * Detects if the application is running in test mode\n *\n * Checks explicitly for NODE_ENV === 'test' in Node.js environments.\n * Vitest and Jest automatically set this value when running tests.\n *\n * @returns True if NODE_ENV is 'test', false otherwise\n *\n * @example\n * ```typescript\n * if (isTest()) {\n * // Test-specific behavior (mocks, fixtures, etc.)\n * enableTestMode()\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Conditional imports for testing\n * if (isTest()) {\n * const { mockAPI } = await import('./test/mocks')\n * mockAPI.setup()\n * }\n * ```\n */\nexport function isTest(): boolean {\n if (isNodeEnvironment()) {\n return process.env.NODE_ENV === 'test'\n }\n\n return false\n}\n\n/**\n * Detects if the application is NOT running in production mode\n *\n * Returns true for development, test, undefined, or any non-production environment.\n * Useful for enabling debugging, logging, or development-only features\n * across all non-production environments.\n *\n * @returns True if not in production (development, test, or undefined)\n *\n * @example\n * ```typescript\n * if (isNonProduction()) {\n * // Enable debug logging for dev and test\n * console.log('Debug mode enabled')\n * enableVerboseLogging()\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Security: Disable strict checks in non-production\n * if (isNonProduction()) {\n * allowSelfSignedCertificates()\n * disableCSRFProtection()\n * }\n * ```\n */\nexport function isNonProduction(): boolean {\n if (isNodeEnvironment()) {\n return process.env.NODE_ENV !== 'production'\n }\n\n return !isProduction()\n}\n\n/**\n * Detects the protocol (HTTP/HTTPS) from browser location or request headers\n *\n * Handles reverse proxies correctly by checking forwarded headers in priority order:\n * 1. X-Forwarded-Proto (most common)\n * 2. X-Forwarded-Protocol\n * 3. X-Url-Scheme\n * 4. Front-End-Https\n * 5. CF-Visitor (Cloudflare specific)\n *\n * @param req - Optional Express request object with headers\n * @returns Protocol as 'http' or 'https'\n *\n * @example\n * ```typescript\n * // Browser usage\n * const protocol = detectProtocol() // 'https' from window.location\n * ```\n *\n * @example\n * ```typescript\n * // Express server with proxy\n * app.get('/api', (req, res) => {\n * const protocol = detectProtocol(req) // Detects from X-Forwarded-Proto\n * const fullUrl = `${protocol}://${req.get('host')}${req.path}`\n * })\n * ```\n */\nexport function detectProtocol(req?: any): 'http' | 'https' {\n if (isBrowserEnvironment()) {\n if (typeof location !== 'undefined') {\n return location.protocol === 'https:' ? 'https' : 'http'\n }\n return 'https' // Default seguro para browser\n }\n\n if (req) {\n // Headers comunes de proxies reversos en orden de prioridad\n const forwardedProto = req.get?.('X-Forwarded-Proto') || req.headers?.['x-forwarded-proto']\n const forwardedProtocol =\n req.get?.('X-Forwarded-Protocol') || req.headers?.['x-forwarded-protocol']\n const urlScheme = req.get?.('X-Url-Scheme') || req.headers?.['x-url-scheme']\n const frontEndHttps = req.get?.('Front-End-Https') || req.headers?.['front-end-https']\n const cloudflareVisitor = req.get?.('CF-Visitor') || req.headers?.['cf-visitor']\n\n // Verificar headers de proxy\n if (forwardedProto) {\n return forwardedProto.split(',')[0].trim().toLowerCase() as 'http' | 'https'\n }\n if (forwardedProtocol) {\n return forwardedProtocol.toLowerCase() as 'http' | 'https'\n }\n if (urlScheme) {\n return urlScheme.toLowerCase() as 'http' | 'https'\n }\n if (frontEndHttps === 'on') {\n return 'https'\n }\n if (cloudflareVisitor) {\n try {\n const visitor = JSON.parse(cloudflareVisitor)\n if (visitor.scheme) {\n return visitor.scheme.toLowerCase() as 'http' | 'https'\n }\n } catch (_e) {\n // Ignorar errores de parsing JSON\n }\n }\n\n // Fallback al protocolo directo\n if (req.protocol) return req.protocol\n if (req.secure) return 'https'\n }\n\n // Default para Node.js sin request context\n return 'http'\n}\n\n/**\n * Extracts hostname from browser location or request headers\n *\n * Handles reverse proxies by checking forwarded headers in priority order:\n * 1. X-Forwarded-Host (most common, supports multiple hosts)\n * 2. X-Original-Host\n * 3. Host header\n *\n * Automatically strips port numbers and handles multiple comma-separated hosts.\n *\n * @param req - Optional Express request object with headers\n * @returns Hostname without port number\n *\n * @example\n * ```typescript\n * // Browser usage\n * const hostname = detectHostname() // 'example.com' from window.location\n * ```\n *\n * @example\n * ```typescript\n * // Express server behind proxy\n * app.get('/api', (req, res) => {\n * const hostname = detectHostname(req) // 'api.example.com' from X-Forwarded-Host\n * const isLocal = isLocalhost(hostname)\n * })\n * ```\n */\nexport function detectHostname(req?: any): string {\n if (isBrowserEnvironment()) {\n if (typeof location !== 'undefined') {\n return location.hostname\n }\n return 'localhost'\n }\n\n if (req) {\n // Headers comunes de proxies reversos en orden de prioridad\n const forwardedHost = req.get?.('X-Forwarded-Host') || req.headers?.['x-forwarded-host']\n const originalHost = req.get?.('X-Original-Host') || req.headers?.['x-original-host']\n const host = req.get?.('Host') || req.headers?.['host']\n\n // Verificar headers de proxy\n if (forwardedHost) {\n return forwardedHost.split(',')[0].trim().split(':')[0]\n }\n if (originalHost) {\n return originalHost.split(':')[0]\n }\n if (host) {\n return host.split(':')[0]\n }\n\n // Fallback al hostname directo\n if (req.hostname) return req.hostname\n }\n\n // Default para Node.js sin request context\n return 'localhost'\n}\n\n/**\n * Checks if a hostname represents localhost or local development\n *\n * Recognizes various localhost representations:\n * - 'localhost' (standard)\n * - '127.0.0.1' (IPv4 loopback)\n * - '::1' (IPv6 loopback)\n * - '*.localhost' (local development domains)\n * - '*.local' (mDNS local domains)\n *\n * @param hostname - Hostname to check\n * @returns True if hostname represents localhost\n *\n * @example\n * ```typescript\n * isLocalhost('localhost') // true\n * isLocalhost('127.0.0.1') // true\n * isLocalhost('app.localhost') // true\n * isLocalhost('macbook.local') // true\n * isLocalhost('example.com') // false\n * ```\n */\nexport function isLocalhost(hostname: string): boolean {\n return (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '::1' ||\n hostname.endsWith('.localhost') ||\n hostname.endsWith('.local')\n )\n}\n\n/**\n * Checks if a hostname is within private IP address ranges\n *\n * Recognizes private/internal IP ranges according to RFC 1918:\n * - IPv4: 10.x.x.x, 192.168.x.x, 172.16-31.x.x, 127.x.x.x (loopback)\n * - IPv6: ::1 (loopback), fc00::/7 (unique local), fe80::/10 (link-local)\n * - Also includes localhost detection\n *\n * @param hostname - Hostname or IP address to check\n * @returns True if hostname is private/local, false if public\n *\n * @example\n * ```typescript\n * isPrivateIP('192.168.1.1') // true\n * isPrivateIP('10.0.0.1') // true\n * isPrivateIP('172.16.0.1') // true\n * isPrivateIP('localhost') // true\n * isPrivateIP('8.8.8.8') // false\n * isPrivateIP('example.com') // false\n * ```\n */\nexport function isPrivateIP(hostname: string): boolean {\n // IPv4 private ranges\n const ipv4Patterns = [\n /^10\\./, // 10.0.0.0/8\n /^172\\.(1[6-9]|2[0-9]|3[0-1])\\./, // 172.16.0.0/12\n /^192\\.168\\./, // 192.168.0.0/16\n /^127\\./, // 127.0.0.0/8 (loopback)\n ]\n\n // IPv6 private/local ranges\n const ipv6Patterns = [\n /^::1$/, // IPv6 loopback\n /^fc[0-9a-f]{2}:/i, // Unique local addresses\n /^fd[0-9a-f]{2}:/i, // Unique local addresses\n /^fe80:/i, // Link-local addresses\n ]\n\n return (\n ipv4Patterns.some(pattern => pattern.test(hostname)) ||\n ipv6Patterns.some(pattern => pattern.test(hostname)) ||\n isLocalhost(hostname)\n )\n}\n\n/**\n * Gathers complete environment information for debugging and analysis\n *\n * Returns comprehensive environment data including platform detection,\n * development/production status, protocol/hostname information, and\n * detailed debugging criteria.\n *\n * @param req - Optional Express request object for server-side context\n * @returns Complete environment information object\n *\n * @example\n * ```typescript\n * // Basic usage\n * const env = getEnvironmentInfo()\n * console.log(env.platform) // 'node' | 'browser' | 'unknown'\n * console.log(env.environment) // 'development' | 'production' | 'test'\n * ```\n *\n * @example\n * ```typescript\n * // Express server usage\n * app.get('/api/debug', (req, res) => {\n * const envInfo = getEnvironmentInfo(req)\n * res.json({\n * platform: envInfo.platform,\n * isDev: envInfo.environment === 'development',\n * protocol: envInfo.protocol,\n * host: envInfo.hostname,\n * criteria: envInfo.criteria\n * })\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Conditional features based on environment\n * const env = getEnvironmentInfo()\n * if (env.criteria?.hasDevtools) {\n * enableVueDevtools()\n * }\n * if (env.criteria?.isDevelopmentPort) {\n * enableHotReload()\n * }\n * ```\n */\nexport function getEnvironmentInfo(req?: any): EnvironmentInfo {\n const platform = isNodeEnvironment() ? 'node' : isBrowserEnvironment() ? 'browser' : 'unknown'\n\n let environment: EnvironmentInfo['environment'] = 'production'\n if (isNodeEnvironment()) {\n const nodeEnv = process.env.NODE_ENV\n if (nodeEnv === 'development' || nodeEnv === 'test') {\n environment = nodeEnv\n }\n } else if (isDevelopment()) {\n environment = 'development'\n }\n\n const protocol = detectProtocol(req)\n const hostname = detectHostname(req)\n\n const info: EnvironmentInfo = {\n platform,\n environment,\n protocol,\n hostname,\n }\n\n if (isBrowserEnvironment() && typeof navigator !== 'undefined') {\n info.userAgent = navigator.userAgent\n }\n\n // Criterios detallados para debugging\n const criteria: EnvironmentCriteria = {\n isLocalhost: isLocalhost(hostname),\n isPrivateIP: isPrivateIP(hostname),\n isDevelopmentPort: false,\n hasDevtools: false,\n }\n\n if (isBrowserEnvironment() && typeof location !== 'undefined') {\n const port = parseInt(location.port || '80')\n criteria.isDevelopmentPort = port >= 3000 && port <= 9999\n criteria.hasDevtools = !!(\n typeof window !== 'undefined' && (window as any).__VUE_DEVTOOLS_GLOBAL_HOOK__\n )\n }\n\n if (isNodeEnvironment()) {\n criteria.nodeEnv = process.env.NODE_ENV || 'undefined'\n }\n\n info.criteria = criteria\n\n return info\n}\n\n/**\n * Alias for isNodeEnvironment() - detects Node.js runtime\n * @see {@link isNodeEnvironment}\n */\nexport const isNode = isNodeEnvironment\n\n/**\n * Alias for isBrowserEnvironment() - detects browser runtime\n * @see {@link isBrowserEnvironment}\n */\nexport const isBrowser = isBrowserEnvironment\n\n/**\n * Parses environment variable string values to their native JavaScript types\n *\n * Automatically detects and converts:\n * - Booleans: 'true', 'false', 'yes', 'no', '1', '0'\n * - Numbers: '42', '3.14', '-100'\n * - JSON arrays: '[1,2,3]', '[\"a\",\"b\"]'\n * - JSON objects: '{\"key\":\"value\"}'\n * - Comma-separated arrays: 'item1,item2,item3' (when not valid JSON)\n * - null/undefined: 'null', 'undefined', empty string\n *\n * Falls back to original string if no conversion applies.\n *\n * @param value - Environment variable string value to parse\n * @returns Parsed value with appropriate native type\n *\n * @example\n * ```typescript\n * // Boolean conversion\n * parseEnvValue('true') // true\n * parseEnvValue('false') // false\n * parseEnvValue('yes') // true\n * parseEnvValue('1') // true (as boolean)\n *\n * // Number conversion\n * parseEnvValue('42') // 42\n * parseEnvValue('3.14') // 3.14\n * parseEnvValue('-100') // -100\n *\n * // JSON arrays\n * parseEnvValue('[1,2,3]') // [1, 2, 3]\n * parseEnvValue('[\"a\",\"b\"]') // ['a', 'b']\n *\n * // JSON objects\n * parseEnvValue('{\"port\":3000,\"host\":\"localhost\"}')\n * // { port: 3000, host: 'localhost' }\n *\n * // Comma-separated arrays (fallback when not JSON)\n * parseEnvValue('red,green,blue') // ['red', 'green', 'blue']\n *\n * // Null/undefined\n * parseEnvValue('null') // null\n * parseEnvValue('undefined') // undefined\n * parseEnvValue('') // undefined\n *\n * // Strings (no conversion)\n * parseEnvValue('hello') // 'hello'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world usage with process.env\n * const config = {\n * debug: parseEnvValue(process.env.DEBUG), // 'true' → true\n * port: parseEnvValue(process.env.PORT), // '3000' → 3000\n * features: parseEnvValue(process.env.FEATURES), // 'auth,api' → ['auth', 'api']\n * database: parseEnvValue(process.env.DB_CONFIG), // '{\"host\":\"localhost\"}' → object\n * }\n * ```\n */\nexport function parseEnvValue(value: string | undefined): any {\n // Handle null/undefined/empty\n if (value === undefined || value === null || value === '') {\n return undefined\n }\n\n const trimmed = value.trim()\n\n // Handle explicit null/undefined strings\n if (trimmed === 'null') return null\n if (trimmed === 'undefined') return undefined\n\n // Handle booleans\n const lowerValue = trimmed.toLowerCase()\n if (lowerValue === 'true' || lowerValue === 'yes') return true\n if (lowerValue === 'false' || lowerValue === 'no') return false\n\n // Handle boolean-like numbers\n if (trimmed === '1') return true\n if (trimmed === '0') return false\n\n // Try parsing as number (but not if it starts with 0 and has more digits - could be octal/string)\n if (/^-?\\d+\\.?\\d*$/.test(trimmed)) {\n // Avoid treating leading-zero strings as numbers (e.g., postal codes '01234')\n if (trimmed.length > 1 && trimmed[0] === '0' && trimmed[1] !== '.') {\n return trimmed // Keep as string (e.g., '01234')\n }\n const num = Number(trimmed)\n if (!isNaN(num)) return num\n }\n\n // Try parsing as JSON (arrays, objects)\n if (\n (trimmed.startsWith('[') && trimmed.endsWith(']')) ||\n (trimmed.startsWith('{') && trimmed.endsWith('}'))\n ) {\n try {\n return JSON.parse(trimmed)\n } catch {\n // Not valid JSON, continue to next check\n }\n }\n\n // Try parsing comma-separated values as array\n if (trimmed.includes(',')) {\n const parts = trimmed.split(',').map(s => s.trim())\n // Only convert to array if all parts are non-empty\n if (parts.every(p => p.length > 0)) {\n return parts\n }\n }\n\n // Return as-is string\n return trimmed\n}\n","/**\n * String manipulation utilities\n * Consolidated from primitives/string module\n */\n\n/**\n * Sanitizes a string by removing special characters and converting to lowercase with dashes\n *\n * Produces clean, URL-friendly strings by removing special characters and normalizing whitespace.\n * Useful for slugs, IDs, CSS class names, and filename generation.\n *\n * Transformation rules:\n * 1. Remove all non-alphanumeric characters except spaces\n * 2. Remove additional punctuation (`~!@#$%^&*()_|+-=?;:'\",.<>{}[]\\\\/`)\n * 3. Replace spaces with dashes\n * 4. Convert to lowercase\n *\n * @param instr - Input string to sanitize (null returns empty string)\n * @returns Sanitized string in lowercase with dashes replacing spaces\n *\n * @example\n * ```typescript\n * // Basic sanitization\n * sanitizeString('Hello World!') // 'hello-world'\n * sanitizeString('user@example.com') // 'userexamplecom'\n * sanitizeString('Price: $19.99') // 'price-1999'\n *\n * // Remove accents and special chars\n * sanitizeString('Café Münchën') // 'caf-mnchen'\n * sanitizeString('北京 2024') // '2024'\n *\n * // Multiple spaces/dashes\n * sanitizeString('hello world') // 'hello---world'\n * sanitizeString('foo-bar_baz') // 'foo-barbaz'\n *\n * // Edge cases\n * sanitizeString(null) // ''\n * sanitizeString('') // ''\n * sanitizeString(' ') // '---'\n * sanitizeString('123') // '123'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate CSS class names from user input\n * function generateClassName(userInput: string): string {\n * return `custom-${sanitizeString(userInput)}`\n * }\n *\n * generateClassName('My Component!') // 'custom-my-component'\n * generateClassName('Button (Primary)') // 'custom-button-primary'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Clean product names for file export\n * const products = [\n * { name: 'T-Shirt (Blue)', sku: 'TS-001' },\n * { name: 'Shoes & Accessories', sku: 'SH-042' }\n * ]\n *\n * products.forEach(p => {\n * const filename = `${sanitizeString(p.name)}-${p.sku}.json`\n * console.log(filename)\n * // 't-shirt-blue-TS-001.json'\n * // 'shoes-accessories-SH-042.json'\n * })\n * ```\n *\n * @see {@link toUrlSlug} for more sophisticated URL slug generation with accent removal\n * @see {@link toKebabCase} for case conversion to kebab-case\n */\nexport const sanitizeString = (instr: string | null): string => {\n if (!instr) return ''\n return addDash(instr.replace(/[^a-zA-Z0-9 ]/g, '')).toLowerCase()\n}\n\nfunction addDash(str: string): string {\n const str2 = str.replace(/[`~!@#$%^&*()_|+\\-=?;:'\",.<>{}[\\]\\\\/]/gi, '')\n return str2.replace(/ /g, '-')\n}\n\n/**\n * Removes JSON-like characters and HTML entities from a string\n * @param texto Input string to clean\n * @returns String with JSON characters and HTML entities removed\n */\nexport const cleanJsonChars = (texto: string | null): string => {\n if (!texto) return ''\n return texto.replace(/({|}|&amp;|amp;|gt;)/g, '')\n}\n\n/**\n * Truncates a string to a specified maximum length with optional suffix\n *\n * Shortens long strings for display in UI components, tables, previews, and tooltips.\n * Preserves readability while fitting space constraints.\n *\n * Behavior:\n * - If string length ≤ maxlength: returns original string unchanged\n * - If string length > maxlength: returns `str.substring(0, maxlength) + suffix`\n * - Suffix is included in addition to maxlength (not counted within limit)\n * - Null/empty strings return empty string\n *\n * @param str - String to truncate (null/empty returns '')\n * @param maxlength - Maximum length before truncation (default: 80 characters)\n * @param suffix - Suffix to append when truncated (default: '...')\n * @returns Truncated string with suffix if needed, original string if shorter\n *\n * @example\n * ```typescript\n * // Basic truncation (default 80 chars)\n * truncateString('Short text') // 'Short text' (no truncation)\n *\n * const long = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'\n * truncateString(long, 20) // 'Lorem ipsum dolor si...' (20 + 3 = 23 chars total)\n *\n * // Custom max length\n * truncateString('Hello World', 5) // 'Hello...'\n * truncateString('Hello World', 11) // 'Hello World' (no truncation)\n *\n * // Custom suffix\n * truncateString('Long text here', 8, '…') // 'Long tex…'\n * truncateString('Long text here', 8, ' [more]') // 'Long tex [more]'\n * truncateString('Long text here', 8, '') // 'Long tex' (no suffix)\n *\n * // Edge cases\n * truncateString('', 10) // ''\n * truncateString(null as any, 10) // '' (graceful handling)\n * truncateString('Hi', 0) // '...' (edge case: 0 maxlength)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Truncate product descriptions in table\n * const products = [\n * { name: 'Laptop', description: 'High-performance laptop with 16GB RAM and 512GB SSD' },\n * { name: 'Mouse', description: 'Wireless ergonomic mouse' }\n * ]\n *\n * products.forEach(p => {\n * console.log(`${p.name}: ${truncateString(p.description, 30)}`)\n * })\n * // Output:\n * // Laptop: High-performance laptop with 1...\n * // Mouse: Wireless ergonomic mouse\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Truncate user comments for preview\n * function renderCommentPreview(comment: string): string {\n * return `<div class=\"preview\">${truncateString(comment, 100)}</div>`\n * }\n *\n * renderCommentPreview('This is a very long comment that needs to be shortened for display...')\n * // '<div class=\"preview\">This is a very long comment that needs to be shortened for display in the UI without taking too m...</div>'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Email subject line truncation\n * function formatEmailSubject(subject: string): string {\n * // Gmail displays ~60 chars on desktop\n * return truncateString(subject, 60, '…')\n * }\n *\n * formatEmailSubject('Re: Important meeting about Q4 planning and budget review')\n * // 'Re: Important meeting about Q4 planning and budget review' (fits)\n *\n * formatEmailSubject('Re: [URGENT] Critical system outage affecting all production servers and databases')\n * // 'Re: [URGENT] Critical system outage affecting all production…'\n * ```\n *\n * @see {@link isEmpty} for checking empty strings\n */\nexport const truncateString = (str: string, maxlength = 80, suffix = '...'): string => {\n if (!str) return ''\n return str.length > maxlength ? str.substring(0, maxlength) + suffix : str\n}\n\n/**\n * Converts Unicode escape sequences to their actual characters\n * @param input String containing Unicode escape sequences\n * @returns String with escape sequences converted to actual characters\n */\nexport const unescapeUnicode = (input: string): string => {\n return JSON.stringify(JSON.parse(`\"${input}\"`)).replace(/^\"(.*)\"$/, '$1')\n}\n\n/**\n * Ensures a string ends with a specific suffix, adding it if not present\n * @param str Input string to check\n * @param trailing Suffix string to ensure is present at the end\n * @returns String guaranteed to end with the trailing string\n */\nexport const ensureEndsWith = (str: string, trailing: string): string => {\n return str.endsWith(trailing) ? str : `${str}${trailing}`\n}\n\n/**\n * Removes a specific suffix from the end of a string if present\n * @param str Input string to process\n * @param trailing Suffix string to remove from the end\n * @returns String with trailing suffix removed, original if suffix not found\n */\nexport const stripFromEnd = (str: string, trailing: string): string => {\n return str.endsWith(trailing) ? str.slice(0, -1 * trailing.length) : str\n}\n\n/**\n * Ensures a string starts with a specific prefix, adding it if not present\n * @param str Input string to check\n * @param leading Prefix string to ensure is present at the start\n * @returns String guaranteed to start with the leading string\n */\nexport const ensureStartsWith = (str: string, leading: string): string => {\n return str.startsWith(leading) ? str : `${leading}${str}`\n}\n\n/**\n * Removes a specific prefix from the start of a string if present\n * @param str Input string to process\n * @param leading Prefix string to remove from the start\n * @returns String with leading prefix removed, original if prefix not found\n */\nexport const stripFromStart = (str: string, leading: string): string => {\n return str.startsWith(leading) ? str.slice(leading.length) : str\n}\n\n/**\n * Converts all characters in a string to lowercase\n * @param str Input string to convert\n * @returns String with all characters in lowercase\n */\nexport const toLowerCase = (str: string): string => {\n return str.toLowerCase()\n}\n\n/**\n * Converts all characters in a string to uppercase\n * @param str Input string to convert\n * @returns String with all characters in uppercase\n */\nexport const toUpperCase = (str: string): string => {\n return str.toUpperCase()\n}\n\n/**\n * Capitalizes the first letter of a string and lowercases the rest\n * @param str Input string to capitalize\n * @returns String with first letter capitalized and rest in lowercase\n */\nexport const capitalizeFirst = (str: string): string => {\n if (!str) return ''\n return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()\n}\n\n/**\n * Capitalizes the first letter of each word in a string\n * @param str Input string with words separated by spaces\n * @returns String with each word's first letter capitalized\n */\nexport const capitalizeEachWord = (str: string): string => {\n if (!str) return ''\n return str\n .split(' ')\n .map(word => capitalizeFirst(word))\n .join(' ')\n}\n\n/**\n * Converts a string to camelCase format\n *\n * Transforms strings from any case convention (kebab-case, snake_case, PascalCase, spaces)\n * to camelCase following JavaScript/TypeScript naming conventions.\n *\n * Algorithm:\n * 1. Detect word boundaries (spaces, hyphens, underscores, case transitions)\n * 2. Split into words and normalize to lowercase\n * 3. First word: keep lowercase\n * 4. Remaining words: capitalize first letter\n * 5. Join without separators\n *\n * Format: `firstWordSecondWordThirdWord`\n *\n * @param str - Input string in any case format (empty returns '')\n * @returns String in camelCase format\n *\n * @example\n * ```typescript\n * // From kebab-case\n * toCamelCase('hello-world') // 'helloWorld'\n * toCamelCase('user-profile-page') // 'userProfilePage'\n *\n * // From snake_case\n * toCamelCase('hello_world') // 'helloWorld'\n * toCamelCase('user_first_name') // 'userFirstName'\n *\n * // From PascalCase\n * toCamelCase('HelloWorld') // 'helloWorld'\n * toCamelCase('UserProfile') // 'userProfile'\n *\n * // From space-separated\n * toCamelCase('hello world') // 'helloWorld'\n * toCamelCase('First Name') // 'firstName'\n *\n * // Mixed formats\n * toCamelCase('hello-World_test') // 'helloWorldTest'\n * toCamelCase('API_Response-data') // 'apiResponseData'\n *\n * // Edge cases\n * toCamelCase('') // ''\n * toCamelCase('a') // 'a'\n * toCamelCase('UPPERCASE') // 'uppercase'\n * toCamelCase('123-test') // '123Test'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Convert database column names to JS properties\n * const dbColumns = ['user_id', 'first_name', 'last_name', 'created_at']\n *\n * const jsProperties = dbColumns.map(toCamelCase)\n * console.log(jsProperties)\n * // ['userId', 'firstName', 'lastName', 'createdAt']\n *\n * // Transform database row to JS object\n * function transformRow(row: Record<string, any>): Record<string, any> {\n * return Object.fromEntries(\n * Object.entries(row).map(([key, value]) => [toCamelCase(key), value])\n * )\n * }\n *\n * transformRow({ user_id: 123, first_name: 'Alice' })\n * // { userId: 123, firstName: 'Alice' }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Convert CSS property names to JS style properties\n * const cssProperties = [\n * 'background-color',\n * 'font-size',\n * 'margin-top',\n * 'border-bottom-width'\n * ]\n *\n * cssProperties.forEach(prop => {\n * const jsProp = toCamelCase(prop)\n * console.log(`${prop} → ${jsProp}`)\n * })\n * // background-color → backgroundColor\n * // font-size → fontSize\n * // margin-top → marginTop\n * // border-bottom-width → borderBottomWidth\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: API response transformation\n * interface ApiUser {\n * user_id: number\n * first_name: string\n * last_name: string\n * created_at: string\n * }\n *\n * function transformApiResponse(apiData: ApiUser) {\n * return {\n * userId: apiData.user_id,\n * firstName: apiData.first_name,\n * lastName: apiData.last_name,\n * createdAt: new Date(apiData.created_at)\n * }\n * }\n *\n * // Or generically:\n * function autoTransformKeys<T extends Record<string, any>>(obj: T) {\n * return Object.fromEntries(\n * Object.entries(obj).map(([k, v]) => [toCamelCase(k), v])\n * )\n * }\n * ```\n *\n * @see {@link toPascalCase} for PascalCase conversion (first letter uppercase)\n * @see {@link toSnakeCase} for snake_case conversion\n * @see {@link toKebabCase} for kebab-case conversion\n */\nexport const toCamelCase = (str: string): string => {\n if (!str) return ''\n\n // Split by word boundaries (spaces, hyphens, underscores, camelCase boundaries)\n const words = str\n .replace(/([a-z])([A-Z])/g, '$1 $2') // Split camelCase\n .split(/[-_\\s]+/) // Split by separators\n .filter(word => word.length > 0)\n .map(word => word.toLowerCase())\n\n if (words.length === 0) return ''\n\n // First word lowercase, rest capitalize first letter\n return (\n words[0] +\n words\n .slice(1)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join('')\n )\n}\n\n/**\n * Converts a string to snake_case format\n *\n * Transforms strings from any case convention to snake_case, commonly used in\n * Python, Ruby, database column names, and environment variables.\n *\n * Algorithm:\n * 1. Replace non-word characters with spaces\n * 2. Split on spaces and camelCase boundaries\n * 3. Convert all words to lowercase\n * 4. Join with underscores\n *\n * Format: `first_word_second_word_third_word`\n *\n * @param str - Input string in any case format (empty returns '')\n * @returns String in snake_case format\n *\n * @example\n * ```typescript\n * // From camelCase\n * toSnakeCase('helloWorld') // 'hello_world'\n * toSnakeCase('userFirstName') // 'user_first_name'\n *\n * // From PascalCase\n * toSnakeCase('HelloWorld') // 'hello_world'\n * toSnakeCase('UserProfile') // 'user_profile'\n *\n * // From kebab-case\n * toSnakeCase('hello-world') // 'hello_world'\n * toSnakeCase('user-profile-page') // 'user_profile_page'\n *\n * // From space-separated\n * toSnakeCase('hello world') // 'hello_world'\n * toSnakeCase('First Name') // 'first_name'\n *\n * // Mixed formats\n * toSnakeCase('helloWorld-test') // 'hello_world_test'\n * toSnakeCase('APIResponse') // 'a_p_i_response'\n *\n * // Edge cases\n * toSnakeCase('') // ''\n * toSnakeCase('a') // 'a'\n * toSnakeCase('UPPERCASE') // 'u_p_p_e_r_c_a_s_e'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Convert JS properties to database column names\n * const jsObject = {\n * userId: 123,\n * firstName: 'Alice',\n * lastName: 'Smith',\n * createdAt: new Date()\n * }\n *\n * const dbColumns = Object.keys(jsObject).map(toSnakeCase)\n * console.log(dbColumns)\n * // ['user_id', 'first_name', 'last_name', 'created_at']\n *\n * // Generate SQL INSERT statement\n * const columns = Object.keys(jsObject).map(toSnakeCase).join(', ')\n * const sql = `INSERT INTO users (${columns}) VALUES (?)`\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Environment variable generation\n * const configKeys = ['databaseHost', 'databasePort', 'apiBaseUrl']\n *\n * configKeys.forEach(key => {\n * const envVar = toSnakeCase(key).toUpperCase()\n * console.log(`${envVar}=value`)\n * })\n * // DATABASE_HOST=value\n * // DATABASE_PORT=value\n * // API_BASE_URL=value\n * ```\n *\n * @see {@link toCamelCase} for camelCase conversion\n * @see {@link toKebabCase} for kebab-case conversion\n * @see {@link toPascalCase} for PascalCase conversion\n */\nexport const toSnakeCase = (str: string): string => {\n if (!str) return ''\n return str\n .replace(/\\W+/g, ' ')\n .split(/ |\\B(?=[A-Z])/)\n .map(word => word.toLowerCase())\n .join('_')\n}\n\n/**\n * Converts a string to kebab-case format\n *\n * Transforms strings from any case convention to kebab-case (also called dash-case or hyphen-case).\n * Widely used in URLs, HTML attributes, CSS classes, and file names.\n *\n * Algorithm:\n * 1. Replace underscores and spaces with hyphens\n * 2. Insert hyphens before uppercase letters (handle camelCase)\n * 3. Convert all to lowercase\n * 4. Remove non-alphanumeric characters (except hyphens)\n * 5. Collapse multiple consecutive hyphens\n * 6. Remove leading/trailing hyphens\n *\n * Format: `first-word-second-word-third-word`\n *\n * @param str - Input string in any case format (empty returns '')\n * @returns String in kebab-case format\n *\n * @example\n * ```typescript\n * // From camelCase\n * toKebabCase('helloWorld') // 'hello-world'\n * toKebabCase('userFirstName') // 'user-first-name'\n *\n * // From PascalCase\n * toKebabCase('HelloWorld') // 'hello-world'\n * toKebabCase('UserProfile') // 'user-profile'\n *\n * // From snake_case\n * toKebabCase('hello_world') // 'hello-world'\n * toKebabCase('user_first_name') // 'user-first-name'\n *\n * // From space-separated\n * toKebabCase('hello world') // 'hello-world'\n * toKebabCase('First Name') // 'first-name'\n *\n * // Mixed formats\n * toKebabCase('helloWorld_test') // 'hello-world-test'\n * toKebabCase('API-Response') // 'api-response'\n *\n * // Edge cases\n * toKebabCase('') // ''\n * toKebabCase('a') // 'a'\n * toKebabCase('UPPERCASE') // 'uppercase'\n * toKebabCase('123Test') // '123-test'\n * toKebabCase('--multiple--dashes--') // 'multiple-dashes'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate URL slugs from page titles\n * const pageTitle = 'My Awesome Blog Post'\n * const urlSlug = toKebabCase(pageTitle)\n * const url = `https://example.com/blog/${urlSlug}`\n * // https://example.com/blog/my-awesome-blog-post\n *\n * // Multiple pages\n * const pages = [\n * { title: 'Getting Started', component: 'GettingStarted' },\n * { title: 'API Reference', component: 'ApiReference' },\n * { title: 'Best Practices', component: 'BestPractices' }\n * ]\n *\n * const routes = pages.map(p => ({\n * path: `/${toKebabCase(p.title)}`,\n * component: p.component\n * }))\n * // [\n * // { path: '/getting-started', component: 'GettingStarted' },\n * // { path: '/api-reference', component: 'ApiReference' },\n * // { path: '/best-practices', component: 'BestPractices' }\n * // ]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: CSS class name generation\n * function generateClassName(componentName: string, modifier?: string): string {\n * const base = `component-${toKebabCase(componentName)}`\n * return modifier ? `${base}--${toKebabCase(modifier)}` : base\n * }\n *\n * generateClassName('UserProfile') // 'component-user-profile'\n * generateClassName('UserProfile', 'isActive') // 'component-user-profile--is-active'\n * generateClassName('ButtonPrimary', 'largeSize') // 'component-button-primary--large-size'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: HTML attribute generation\n * function generateDataAttribute(key: string, value: string): string {\n * return `data-${toKebabCase(key)}=\"${value}\"`\n * }\n *\n * generateDataAttribute('userId', '123') // 'data-user-id=\"123\"'\n * generateDataAttribute('testEnvironment', 'staging') // 'data-test-environment=\"staging\"'\n * ```\n *\n * @see {@link toCamelCase} for camelCase conversion\n * @see {@link toSnakeCase} for snake_case conversion\n * @see {@link toPascalCase} for PascalCase conversion\n * @see {@link toUrlSlug} for URL-safe slug generation with accent removal\n */\nexport const toKebabCase = (str: string): string => {\n if (!str) return ''\n return str\n .replace(/[_\\s]+/g, '-')\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2') // Handle numbers before capitals too\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n}\n\n/**\n * Converts a string to PascalCase format\n *\n * Transforms strings from any case convention to PascalCase (also called UpperCamelCase).\n * Commonly used for class names, component names, type names, and constructor functions\n * in JavaScript/TypeScript.\n *\n * Algorithm:\n * 1. Split on word boundaries (hyphens, underscores, spaces)\n * 2. Capitalize first letter of each word\n * 3. Join without separators\n * 4. Ensure first character is uppercase\n *\n * Format: `FirstWordSecondWordThirdWord`\n *\n * @param str - Input string in any case format (empty returns '')\n * @returns String in PascalCase format\n *\n * @example\n * ```typescript\n * // From camelCase\n * toPascalCase('helloWorld') // 'HelloWorld'\n * toPascalCase('userFirstName') // 'UserFirstName'\n *\n * // From kebab-case\n * toPascalCase('hello-world') // 'HelloWorld'\n * toPascalCase('user-profile-page') // 'UserProfilePage'\n *\n * // From snake_case\n * toPascalCase('hello_world') // 'HelloWorld'\n * toPascalCase('user_first_name') // 'UserFirstName'\n *\n * // From space-separated\n * toPascalCase('hello world') // 'HelloWorld'\n * toPascalCase('first name') // 'FirstName'\n *\n * // Mixed formats\n * toPascalCase('hello-World_test') // 'HelloWorldTest'\n * toPascalCase('api_response-data') // 'ApiResponseData'\n *\n * // Edge cases\n * toPascalCase('') // ''\n * toPascalCase('a') // 'A'\n * toPascalCase('UPPERCASE') // 'UPPERCASE'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate React component names\n * const componentNames = ['user-profile', 'navigation-bar', 'footer-links']\n *\n * componentNames.forEach(name => {\n * const pascalName = toPascalCase(name)\n * console.log(`export function ${pascalName}() { ... }`)\n * })\n * // export function UserProfile() { ... }\n * // export function NavigationBar() { ... }\n * // export function FooterLinks() { ... }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: TypeScript type name generation\n * interface GenerateTypeOptions {\n * name: string\n * fields: Array<{ name: string; type: string }>\n * }\n *\n * function generateTypeDefinition(options: GenerateTypeOptions): string {\n * const typeName = toPascalCase(options.name)\n * const fields = options.fields\n * .map(f => ` ${f.name}: ${f.type}`)\n * .join('\\n')\n *\n * return `interface ${typeName} {\\n${fields}\\n}`\n * }\n *\n * generateTypeDefinition({\n * name: 'user-profile',\n * fields: [\n * { name: 'userId', type: 'number' },\n * { name: 'name', type: 'string' }\n * ]\n * })\n * // interface UserProfile {\n * // userId: number\n * // name: string\n * // }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Class name generation for dynamic imports\n * async function loadService(serviceName: string) {\n * const className = toPascalCase(serviceName)\n * const module = await import(`./services/${serviceName}`)\n * return new module[className]()\n * }\n *\n * await loadService('user-service') // new UserService()\n * await loadService('payment-gateway') // new PaymentGateway()\n * ```\n *\n * @see {@link toCamelCase} for camelCase conversion (first letter lowercase)\n * @see {@link toSnakeCase} for snake_case conversion\n * @see {@link toKebabCase} for kebab-case conversion\n */\nexport const toPascalCase = (str: string): string => {\n if (!str) return ''\n return str\n .replace(/[-_\\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))\n .replace(/^./, char => char.toUpperCase())\n}\n\n/**\n * Checks if a string contains another string with optional case sensitivity\n * @param str String to search within\n * @param searchStr Substring to search for\n * @param caseSensitive Whether to perform case-sensitive search (default: false)\n * @returns True if the string contains the search string, false otherwise\n */\nexport const contains = (str: string, searchStr: string, caseSensitive = false): boolean => {\n if (caseSensitive) {\n return str.includes(searchStr)\n }\n return str.toLowerCase().includes(searchStr.toLowerCase())\n}\n\n/**\n * Checks if a string starts with another string with optional case sensitivity\n * @param str String to check\n * @param searchStr Prefix to search for\n * @param caseSensitive Whether to perform case-sensitive search (default: false)\n * @returns True if the string starts with the search string, false otherwise\n */\nexport const startsWith = (str: string, searchStr: string, caseSensitive = false): boolean => {\n if (caseSensitive) {\n return str.startsWith(searchStr)\n }\n return str.toLowerCase().startsWith(searchStr.toLowerCase())\n}\n\n/**\n * Checks if a string ends with another string with optional case sensitivity\n * @param str String to check\n * @param searchStr Suffix to search for\n * @param caseSensitive Whether to perform case-sensitive search (default: false)\n * @returns True if the string ends with the search string, false otherwise\n */\nexport const endsWith = (str: string, searchStr: string, caseSensitive = false): boolean => {\n if (caseSensitive) {\n return str.endsWith(searchStr)\n }\n return str.toLowerCase().endsWith(searchStr.toLowerCase())\n}\n\n/**\n * Pads a string at the start (left) with a specific character to reach target length\n * @param str String to pad\n * @param length Target length for the resulting string\n * @param padChar Character to use for padding (default: space)\n * @returns String padded to target length, original if already longer\n */\nexport const padStart = (str: string, length: number, padChar = ' '): string => {\n return str.padStart(length, padChar)\n}\n\n/**\n * Pads a string at the end (right) with a specific character to reach target length\n * @param str String to pad\n * @param length Target length for the resulting string\n * @param padChar Character to use for padding (default: space)\n * @returns String padded to target length, original if already longer\n */\nexport const padEnd = (str: string, length: number, padChar = ' '): string => {\n if (str.length >= length) return str\n return str + padChar.repeat(length - str.length)\n}\n\n/**\n * Removes leading and trailing whitespace from a string\n * @param str String to trim\n * @returns String with leading and trailing whitespace removed\n */\nexport const trim = (str: string): string => {\n return str.trim()\n}\n\n/**\n * Removes leading (start) whitespace from a string\n * @param str String to trim\n * @returns String with leading whitespace removed\n */\nexport const trimStart = (str: string): string => {\n return str.trimStart()\n}\n\n/**\n * Removes trailing (end) whitespace from a string\n * @param str String to trim\n * @returns String with trailing whitespace removed\n */\nexport const trimEnd = (str: string): string => {\n return str.trimEnd()\n}\n\n/**\n * Reverses the character order in a string\n * @param str String to reverse\n * @returns String with characters in reverse order\n */\nexport const reverseString = (str: string): string => {\n return str.split('').reverse().join('')\n}\n\n/**\n * Repeats a string a specified number of times\n * @param str String to repeat\n * @param times Number of times to repeat the string\n * @returns String repeated the specified number of times\n */\nexport const repeatString = (str: string, times: number): string => {\n return str.repeat(times)\n}\n\n/**\n * Replaces all occurrences of a substring with a replacement string\n * @param str String to search in\n * @param searchStr Substring to find and replace\n * @param replaceStr String to replace each occurrence with\n * @returns String with all occurrences replaced\n */\nexport const replaceAllOccurrences = (\n str: string,\n searchStr: string,\n replaceStr: string\n): string => {\n return str.split(searchStr).join(replaceStr)\n}\n\n/**\n * Counts the number of occurrences of a substring within a string\n * @param str String to search within\n * @param searchStr Substring to count occurrences of\n * @returns Number of times the substring appears in the string\n */\nexport const countOccurrences = (str: string, searchStr: string): number => {\n if (!searchStr) return 0\n let count = 0\n let position = 0\n\n while ((position = str.indexOf(searchStr, position)) !== -1) {\n count++\n position += 1 // Move only 1 position to allow overlapping matches\n }\n\n return count\n}\n\n/**\n * Checks if a string is empty, null, undefined, or contains only whitespace\n * @param str String to check (can be null or undefined)\n * @returns True if string is empty/null/undefined or only whitespace, false otherwise\n */\nexport const isEmpty = (str: string | null | undefined): boolean => {\n return !str || str.trim().length === 0\n}\n\n/**\n * Validates if a string is a properly formatted email address\n * @param str String to validate as email\n * @returns True if string matches email format, false otherwise\n */\nexport const isEmail = (str: string): boolean => {\n const re =\n /^(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/\n return re.test(str.toLowerCase())\n}\n\n/**\n * Generates a URL-friendly slug from a string\n *\n * Creates clean, SEO-friendly URL slugs by normalizing strings for use in web addresses.\n * Removes special characters, normalizes whitespace, and converts to lowercase with hyphens.\n *\n * Algorithm:\n * 1. Convert to lowercase\n * 2. Trim leading/trailing whitespace\n * 3. Remove non-word characters (except spaces, hyphens, underscores)\n * 4. Replace spaces/underscores/multiple-hyphens with single hyphen\n * 5. Remove leading/trailing hyphens\n *\n * Format: `url-friendly-slug-text`\n *\n * ⚠️ NOTE: Does NOT remove accents. For accent removal, use {@link removeAccents} first.\n *\n * @param str - String to convert to URL slug (special chars removed)\n * @returns URL-friendly slug string in lowercase with hyphens\n *\n * @example\n * ```typescript\n * // Basic slug generation\n * toUrlSlug('Hello World') // 'hello-world'\n * toUrlSlug('My Blog Post Title') // 'my-blog-post-title'\n *\n * // Remove special characters\n * toUrlSlug('User: John Doe!') // 'user-john-doe'\n * toUrlSlug('Price: $19.99') // 'price-1999'\n * toUrlSlug('Hello @ World #2024') // 'hello-world-2024'\n *\n * // Normalize whitespace and separators\n * toUrlSlug('hello world') // 'hello-world'\n * toUrlSlug('hello_world_test') // 'hello-world-test'\n * toUrlSlug('---multiple---dashes---') // 'multiple-dashes'\n *\n * // Preserve numbers and hyphens\n * toUrlSlug('Article 123') // 'article-123'\n * toUrlSlug('ES6-Features') // 'es6-features'\n *\n * // Edge cases\n * toUrlSlug('') // ''\n * toUrlSlug(' ') // ''\n * toUrlSlug('123') // '123'\n * toUrlSlug('a-b-c') // 'a-b-c'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate blog post URL from title\n * function createBlogPostUrl(title: string, id: number): string {\n * const slug = toUrlSlug(title)\n * return `/blog/${id}/${slug}`\n * }\n *\n * createBlogPostUrl('10 Tips for TypeScript', 42)\n * // '/blog/42/10-tips-for-typescript'\n *\n * createBlogPostUrl('Getting Started with React!', 1)\n * // '/blog/1/getting-started-with-react'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate product URLs for e-commerce\n * interface Product {\n * id: string\n * name: string\n * category: string\n * }\n *\n * function getProductUrl(product: Product): string {\n * const categorySlug = toUrlSlug(product.category)\n * const nameSlug = toUrlSlug(product.name)\n * return `/products/${categorySlug}/${product.id}/${nameSlug}`\n * }\n *\n * getProductUrl({\n * id: 'SKU-123',\n * name: 'Wireless Mouse (Ergonomic)',\n * category: 'Computer Accessories'\n * })\n * // '/products/computer-accessories/SKU-123/wireless-mouse-ergonomic'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: SEO-friendly URLs with accent handling\n * function createSeoUrl(title: string): string {\n * // Remove accents BEFORE slug generation for better URL compatibility\n * return toUrlSlug(removeAccents(title))\n * }\n *\n * createSeoUrl('Café Münchën 2024')\n * // 'cafe-munchen-2024' (accents removed)\n *\n * // Without accent removal:\n * toUrlSlug('Café Münchën 2024')\n * // 'caf-mnchen-2024' (accents become invalid chars, get removed)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate unique slugs for duplicate titles\n * const existingSlugs = new Set(['hello-world', 'hello-world-1'])\n *\n * function generateUniqueSlug(title: string): string {\n * let slug = toUrlSlug(title)\n * let counter = 1\n *\n * while (existingSlugs.has(slug)) {\n * slug = `${toUrlSlug(title)}-${counter}`\n * counter++\n * }\n *\n * existingSlugs.add(slug)\n * return slug\n * }\n *\n * generateUniqueSlug('Hello World') // 'hello-world-2' (avoiding existing)\n * generateUniqueSlug('New Article') // 'new-article'\n * ```\n *\n * @see {@link toKebabCase} for case conversion to kebab-case\n * @see {@link removeAccents} for removing accents before slug generation\n * @see {@link sanitizeString} for basic string sanitization\n */\nexport const toUrlSlug = (str: string): string => {\n return str\n .toLowerCase()\n .trim()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/[\\s_-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n}\n\n/**\n * Removes accents and diacritical marks from characters in a string\n *\n * Uses Unicode normalization (NFD) to decompose accented characters, then removes\n * combining diacritical marks. Essential for search, sorting, URL slugs, and ASCII compatibility.\n *\n * Algorithm:\n * 1. Normalize string to NFD (Normalization Form Decomposed)\n * 2. Remove Unicode combining diacritical marks (U+0300–U+036F)\n * 3. Return ASCII-compatible base characters\n *\n * Supported diacritics: acute (´), grave (`), circumflex (^), tilde (~), umlaut (¨),\n * cedilla (¸), and many more.\n *\n * @param str - String containing accented characters (e.g., 'café', 'Münchën')\n * @returns String with accents removed to base ASCII characters (e.g., 'cafe', 'Munchen')\n *\n * @example\n * ```typescript\n * // Basic accent removal - Romance languages\n * removeAccents('café') // 'cafe'\n * removeAccents('naïve') // 'naive'\n * removeAccents('résumé') // 'resume'\n * removeAccents('à côté') // 'a cote'\n *\n * // Spanish accents\n * removeAccents('Español') // 'Espanol'\n * removeAccents('niño') // 'nino'\n * removeAccents('José María') // 'Jose Maria'\n *\n * // German umlauts\n * removeAccents('Münchën') // 'Munchen'\n * removeAccents('Köln') // 'Koln'\n * removeAccents('Zürich') // 'Zurich'\n *\n * // Portuguese\n * removeAccents('São Paulo') // 'Sao Paulo'\n * removeAccents('Brasília') // 'Brasilia'\n *\n * // French\n * removeAccents('Côte d'Ivoire') // 'Cote d'Ivoire'\n * removeAccents('Françoise') // 'Francoise'\n *\n * // Mixed\n * removeAccents('Crème brûlée') // 'Creme brulee'\n * removeAccents('Åre, Malmö') // 'Are, Malmo'\n *\n * // Edge cases\n * removeAccents('') // ''\n * removeAccents('ASCII text') // 'ASCII text' (unchanged)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Search normalization (case + accent insensitive)\n * function normalizeForSearch(text: string): string {\n * return removeAccents(text.toLowerCase().trim())\n * }\n *\n * const searchQuery = normalizeForSearch('Café') // 'cafe'\n * const productName = normalizeForSearch('CAFÉ PREMIUM') // 'cafe premium'\n *\n * if (productName.includes(searchQuery)) {\n * console.log('Match found!')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate SEO-friendly URLs\n * function createSeoUrl(title: string): string {\n * return toUrlSlug(removeAccents(title))\n * }\n *\n * createSeoUrl('Guía de Español')\n * // 'guia-de-espanol'\n *\n * createSeoUrl('Café Münchën 2024')\n * // 'cafe-munchen-2024'\n *\n * createSeoUrl('São Paulo: Best Restaurants')\n * // 'sao-paulo-best-restaurants'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sort names alphabetically (accent-insensitive)\n * const names = ['Álvarez', 'Andersen', 'Ängel', 'Adams']\n *\n * const sorted = names.sort((a, b) =>\n * removeAccents(a).localeCompare(removeAccents(b))\n * )\n * // ['Adams', 'Álvarez', 'Andersen', 'Ängel']\n * // (sorted by: Adams, Alvarez, Andersen, Angel)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Filename sanitization\n * function sanitizeFilename(filename: string): string {\n * // Remove accents, then sanitize\n * const withoutAccents = removeAccents(filename)\n * return sanitizeString(withoutAccents)\n * }\n *\n * sanitizeFilename('Presentación_2024.pdf')\n * // 'presentacion-2024pdf'\n *\n * sanitizeFilename('Föräldrar & Barn.docx')\n * // 'foraldrar-barn-docx'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Email address generation\n * function generateEmail(firstName: string, lastName: string): string {\n * const first = removeAccents(firstName.toLowerCase())\n * const last = removeAccents(lastName.toLowerCase())\n * return `${first}.${last}@company.com`\n * }\n *\n * generateEmail('José', 'García')\n * // 'jose.garcia@company.com'\n *\n * generateEmail('François', 'Müller')\n * // 'francois.muller@company.com'\n * ```\n *\n * @see {@link toUrlSlug} for URL slug generation (combine with removeAccents for best results)\n * @see {@link sanitizeString} for string sanitization\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize String.normalize() Documentation}\n */\nexport const removeAccents = (str: string): string => {\n return str.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n}\n\n/**\n * Escapes HTML special characters to prevent XSS and display issues\n *\n * Converts dangerous HTML characters to their HTML entity equivalents, preventing\n * script injection (XSS) and ensuring proper text display in HTML contexts.\n *\n * Escaped characters:\n * - `&` → `&amp;` (must be first to avoid double-escaping)\n * - `<` → `&lt;` (prevents opening tags)\n * - `>` → `&gt;` (prevents closing tags)\n * - `\"` → `&quot;` (prevents attribute injection)\n * - `'` → `&#39;` (prevents attribute injection)\n *\n * ⚠️ SECURITY WARNING: This provides basic XSS protection but is NOT a complete solution.\n * For production HTML sanitization, use DOMPurify or similar dedicated libraries.\n * This function is safe for:\n * - Displaying user input as plain text in HTML\n * - Escaping attribute values in HTML\n * - Simple content rendering\n *\n * NOT sufficient for:\n * - Rich HTML content (use DOMPurify)\n * - JavaScript context (use different escaping)\n * - URL context (use encodeURIComponent)\n * - CSS context (use CSS-specific escaping)\n *\n * @param str - String containing HTML characters to escape\n * @returns String with HTML characters safely escaped as HTML entities\n *\n * @example\n * ```typescript\n * // Basic escaping\n * escapeHtmlChars('<script>alert(\"XSS\")</script>')\n * // '&lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;'\n *\n * escapeHtmlChars('5 < 10 & 10 > 5')\n * // '5 &lt; 10 &amp; 10 &gt; 5'\n *\n * escapeHtmlChars('Say \"Hello\" & \\'Goodbye\\'')\n * // 'Say &quot;Hello&quot; &amp; &#39;Goodbye&#39;'\n *\n * // Edge cases\n * escapeHtmlChars('') // ''\n * escapeHtmlChars('No special chars') // 'No special chars'\n * escapeHtmlChars('&lt;') // '&amp;lt;' (escapes already-escaped)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Safely display user comments in HTML\n * interface Comment {\n * author: string\n * content: string\n * }\n *\n * function renderComment(comment: Comment): string {\n * const safeAuthor = escapeHtmlChars(comment.author)\n * const safeContent = escapeHtmlChars(comment.content)\n *\n * return `\n * <div class=\"comment\">\n * <strong>${safeAuthor}</strong>\n * <p>${safeContent}</p>\n * </div>\n * `\n * }\n *\n * renderComment({\n * author: '<script>alert(\"XSS\")</script>',\n * content: 'Great post! <3'\n * })\n * // Safe HTML output with escaped tags\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate safe HTML attributes\n * function generateDataAttribute(key: string, value: string): string {\n * const safeKey = toKebabCase(key)\n * const safeValue = escapeHtmlChars(value)\n * return `data-${safeKey}=\"${safeValue}\"`\n * }\n *\n * generateDataAttribute('userInput', '<script>alert(1)</script>')\n * // 'data-user-input=\"&lt;script&gt;alert(1)&lt;/script&gt;\"'\n *\n * generateDataAttribute('description', 'Product \"Premium\" & more')\n * // 'data-description=\"Product &quot;Premium&quot; &amp; more\"'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Escape user search query for display\n * function displaySearchResults(query: string, results: any[]): string {\n * const safeQuery = escapeHtmlChars(query)\n *\n * return `\n * <div class=\"search-results\">\n * <h2>Results for: ${safeQuery}</h2>\n * <p>${results.length} results found</p>\n * </div>\n * `\n * }\n *\n * displaySearchResults('<img src=x onerror=alert(1)>', [])\n * // Safe display: \"Results for: &lt;img src=x onerror=alert(1)&gt;\"\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: CSV to HTML table with safe content\n * function csvRowToHtmlRow(cells: string[]): string {\n * const safeCells = cells.map(cell => escapeHtmlChars(cell))\n * const tdElements = safeCells.map(cell => `<td>${cell}</td>`).join('')\n * return `<tr>${tdElements}</tr>`\n * }\n *\n * csvRowToHtmlRow(['Alice', '<script>evil</script>', '25'])\n * // '<tr><td>Alice</td><td>&lt;script&gt;evil&lt;/script&gt;</td><td>25</td></tr>'\n * ```\n *\n * @example\n * ```typescript\n * // Edge case: Preventing double-escaping\n * const userInput = 'Hello & Goodbye'\n * const escaped = escapeHtmlChars(userInput)\n * // 'Hello &amp; Goodbye'\n *\n * const doubleEscaped = escapeHtmlChars(escaped)\n * // 'Hello &amp;amp; Goodbye' ⚠️ Over-escaped!\n *\n * // Solution: Only escape once, track escaped state\n * interface SafeString {\n * value: string\n * isEscaped: boolean\n * }\n *\n * function safeEscape(str: string | SafeString): SafeString {\n * if (typeof str === 'object' && str.isEscaped) {\n * return str\n * }\n * const value = typeof str === 'string' ? str : str.value\n * return { value: escapeHtmlChars(value), isEscaped: true }\n * }\n * ```\n *\n * @see {@link unescapeHtmlChars} for reversing HTML entity escaping\n * @see {@link sanitizeString} for basic string sanitization\n * @see {@link https://owasp.org/www-community/attacks/xss/ OWASP XSS Prevention Cheat Sheet}\n * @see {@link https://github.com/cure53/DOMPurify DOMPurify for production HTML sanitization}\n */\nexport const escapeHtmlChars = (str: string): string => {\n const htmlEscapes: { [key: string]: string } = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n }\n return str.replace(/[&<>\"']/g, match => htmlEscapes[match])\n}\n\n/**\n * Converts HTML entities back to their original characters\n * @param str String containing HTML entities to unescape\n * @returns String with HTML entities converted back to original characters\n */\nexport const unescapeHtmlChars = (str: string): string => {\n const htmlUnescapes: { [key: string]: string } = {\n '&amp;': '&',\n '&lt;': '<',\n '&gt;': '>',\n '&quot;': '\"',\n '&#39;': \"'\",\n }\n return str.replace(/&amp;|&lt;|&gt;|&quot;|&#39;/g, match => htmlUnescapes[match])\n}\n\n/**\n * Checks if a path matches a wildcard pattern using dot notation\n *\n * Supports wildcards (*) to match any segment at that position.\n * Useful for configuration paths, routing, permissions, and feature flags.\n *\n * @param path - Dot-notation path to test (e.g., 'features.auth.enabled')\n * @param pattern - Pattern with optional wildcards (e.g., 'features.*', 'features.*.enabled')\n * @returns True if path matches pattern, false otherwise\n *\n * @example\n * ```typescript\n * // Exact match\n * matchPathPattern('features.auth', 'features.auth') // true\n *\n * // Wildcard at end\n * matchPathPattern('features.auth', 'features.*') // true\n * matchPathPattern('features.payments', 'features.*') // true\n * matchPathPattern('other.value', 'features.*') // false\n *\n * // Wildcard in middle\n * matchPathPattern('features.auth.enabled', 'features.*.enabled') // true\n * matchPathPattern('features.payments.enabled', 'features.*.enabled') // true\n * matchPathPattern('features.auth.disabled', 'features.*.enabled') // false\n *\n * // Multiple wildcards\n * matchPathPattern('app.features.auth.oauth', 'app.*.*.oauth') // true\n * matchPathPattern('app.features.auth.saml', 'app.*.*.oauth') // false\n *\n * // No wildcard\n * matchPathPattern('exact.path.match', 'exact.path.match') // true\n * matchPathPattern('exact.path.nomatch', 'exact.path.match') // false\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Feature flag matching\n * const enabledFeatures = [\n * 'features.auth.oauth',\n * 'features.auth.saml',\n * 'features.payments.stripe',\n * ]\n *\n * const hasAuth = enabledFeatures.some(f =>\n * matchPathPattern(f, 'features.auth.*')\n * ) // true\n *\n * const hasPayments = enabledFeatures.some(f =>\n * matchPathPattern(f, 'features.payments.*')\n * ) // true\n *\n * // Permission matching\n * const userPermissions = ['admin.users.read', 'admin.users.write']\n * const canManageUsers = userPermissions.some(p =>\n * matchPathPattern(p, 'admin.users.*')\n * ) // true\n * ```\n */\nexport function matchPathPattern(path: string, pattern: string): boolean {\n if (!path || typeof path !== 'string' || !pattern || typeof pattern !== 'string') {\n return false\n }\n\n // Exact match\n if (path === pattern) {\n return true\n }\n\n // No wildcard in pattern\n if (!pattern.includes('*')) {\n return path === pattern\n }\n\n // Convert pattern to regex\n // Escape special regex characters except *\n const regexPattern = pattern\n .split('.')\n .map(segment => {\n if (segment === '*') {\n return '[^.]+'\n }\n // Escape special regex chars\n return segment.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n })\n .join('\\\\.')\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(path)\n}\n\n/**\n * Converts an environment variable key to dot-notation path\n *\n * Transforms uppercase underscore-separated env var names to lowercase\n * dot-notation paths. Optionally removes a prefix.\n *\n * Common convention: ENV_VAR_NAME → env.var.name\n *\n * @param envKey - Environment variable key (e.g., 'NX_FEATURES_AUTH', 'APP_DATABASE_HOST')\n * @param prefix - Optional prefix to remove (e.g., 'NX', 'APP'). Default: 'NX'\n * @returns Dot-notation path in lowercase\n *\n * @example\n * ```typescript\n * // Default prefix (NX)\n * envKeyToPath('NX_FEATURES_AUTH') // 'features.auth'\n * envKeyToPath('NX_FEATURES_PAYMENTS') // 'features.payments'\n * envKeyToPath('NX_DATABASE_HOST') // 'database.host'\n *\n * // Custom prefix\n * envKeyToPath('APP_DATABASE_HOST', 'APP') // 'database.host'\n * envKeyToPath('MY_CONFIG_VALUE', 'MY') // 'config.value'\n *\n * // No prefix\n * envKeyToPath('DATABASE_HOST', '') // 'database.host'\n * envKeyToPath('FEATURES_AUTH', '') // 'features.auth'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Parse environment variables to config object\n * const envVars = {\n * 'APP_DATABASE_HOST': 'localhost',\n * 'APP_DATABASE_PORT': '5432',\n * 'APP_CACHE_TTL': '3600',\n * }\n *\n * const config = {}\n * Object.entries(envVars).forEach(([key, value]) => {\n * const path = envKeyToPath(key, 'APP')\n * // Use with setDeepValue: setDeepValue(config, path, value)\n * })\n * // Paths: 'database.host', 'database.port', 'cache.ttl'\n * ```\n */\nexport function envKeyToPath(envKey: string, prefix: string = 'NX'): string {\n if (!envKey || typeof envKey !== 'string') {\n return ''\n }\n\n let key = envKey.trim()\n\n // Remove prefix if provided and matches\n if (prefix && key.startsWith(`${prefix}_`)) {\n key = key.substring(prefix.length + 1)\n }\n\n // Convert to lowercase and replace underscores with dots\n return key.toLowerCase().replace(/_/g, '.')\n}\n\n/**\n * Converts a dot-notation path to environment variable key format\n *\n * Transforms lowercase dot-notation paths to uppercase underscore-separated\n * env var names. Optionally adds a prefix.\n *\n * Common convention: env.var.name → ENV_VAR_NAME\n *\n * @param path - Dot-notation path (e.g., 'features.auth', 'database.host')\n * @param prefix - Optional prefix to add (e.g., 'NX', 'APP'). Default: 'NX'\n * @returns Environment variable key in uppercase\n *\n * @example\n * ```typescript\n * // Default prefix (NX)\n * pathToEnvKey('features.auth') // 'NX_FEATURES_AUTH'\n * pathToEnvKey('features.payments') // 'NX_FEATURES_PAYMENTS'\n * pathToEnvKey('database.host') // 'NX_DATABASE_HOST'\n *\n * // Custom prefix\n * pathToEnvKey('database.host', 'APP') // 'APP_DATABASE_HOST'\n * pathToEnvKey('config.value', 'MY') // 'MY_CONFIG_VALUE'\n *\n * // No prefix\n * pathToEnvKey('database.host', '') // 'DATABASE_HOST'\n * pathToEnvKey('features.auth', '') // 'FEATURES_AUTH'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate .env file from config object\n * const config = {\n * database: { host: 'localhost', port: 5432 },\n * cache: { ttl: 3600 }\n * }\n *\n * const envVars = [\n * `${pathToEnvKey('database.host', 'APP')}=localhost`,\n * `${pathToEnvKey('database.port', 'APP')}=5432`,\n * `${pathToEnvKey('cache.ttl', 'APP')}=3600`,\n * ]\n * // Output:\n * // APP_DATABASE_HOST=localhost\n * // APP_DATABASE_PORT=5432\n * // APP_CACHE_TTL=3600\n * ```\n */\nexport function pathToEnvKey(path: string, prefix: string = 'NX'): string {\n if (!path || typeof path !== 'string') {\n return ''\n }\n\n // Convert dots to underscores and uppercase\n const key = path.trim().toUpperCase().replace(/\\./g, '_')\n\n // Return empty if path was just whitespace\n if (key.length === 0) {\n return ''\n }\n\n // Add prefix if provided\n if (prefix && prefix.length > 0) {\n return `${prefix.toUpperCase()}_${key}`\n }\n\n return key\n}\n","/**\n * Object manipulation and comparison utilities\n * Consolidated from primitives/object and array modules\n */\n\nimport crc32 from 'crc/crc32'\nimport * as lodash from 'lodash'\nconst {\n isArray,\n isArrayBuffer,\n isBoolean,\n isBuffer,\n isEqual,\n isNil,\n isNumber,\n isObject,\n isPlainObject,\n isString,\n isTypedArray,\n transform,\n} = lodash\nimport fastEqual from 'fast-deep-equal'\nimport { areDatesEqualWithTolerance, isDateTime, toDate } from './dates'\n\n// Native implementations to replace lodash functions\nconst nativeFilter = <T>(array: T[], predicate: Partial<T>): T[] => {\n return array.filter(item => {\n return Object.keys(predicate).every(key => item[key as keyof T] === predicate[key as keyof T])\n })\n}\n\nconst nativeAssign = <T extends object>(target: T, source: Partial<T>): T => {\n return Object.assign(target, source)\n}\n\nconst nativePick = <T extends object, K extends keyof T>(object: T, keys: K[]): Pick<T, K> => {\n const result = {} as Pick<T, K>\n keys.forEach(key => {\n if (key in object) {\n result[key] = object[key]\n }\n })\n return result\n}\n\nconst nativeRemove = <T>(array: T[], predicate: (item: T) => boolean): T[] => {\n const removed: T[] = []\n for (let i = array.length - 1; i >= 0; i--) {\n if (predicate(array[i])) {\n removed.unshift(array.splice(i, 1)[0])\n }\n }\n return removed\n}\n\n/**\n * Compares two objects utilizing lodash deep comparison\n * @deprecated Use `deepEqual` instead for consistency\n * @param data1 First object to compare\n * @param data2 Second object to compare\n * @returns True if objects are deeply equal, false otherwise\n */\nexport const comparator = (data1: any, data2: any) => isEqual(data1, data2)\n\n/**\n * Performs fast deep comparison between two values\n *\n * Compares values recursively including nested objects, arrays, dates, RegExp, and primitives.\n * Uses fast-deep-equal library for optimal performance (~5-10x faster than JSON.stringify).\n *\n * Comparison rules:\n * - Primitives: strict equality (===)\n * - Objects: recursive key-value comparison\n * - Arrays: length + element-by-element comparison\n * - Dates: compares timestamps\n * - RegExp: compares source and flags\n * - null/undefined: strict equality\n *\n * Use cases: Testing, change detection, cache invalidation, data validation\n *\n * @param data1 - First value to compare (any type)\n * @param data2 - Second value to compare (any type)\n * @returns True if values are deeply equal, false otherwise\n *\n * @example\n * ```typescript\n * // Primitive values\n * deepEqual(42, 42) // true\n * deepEqual('hello', 'hello') // true\n * deepEqual(null, null) // true\n * deepEqual(42, '42') // false (different types)\n *\n * // Objects\n * deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 }) // true\n * deepEqual({ a: 1, b: 2 }, { b: 2, a: 1 }) // true (order doesn't matter)\n * deepEqual({ a: 1 }, { a: 1, b: undefined }) // false\n *\n * // Arrays\n * deepEqual([1, 2, 3], [1, 2, 3]) // true\n * deepEqual([1, 2, 3], [3, 2, 1]) // false (order matters)\n *\n * // Nested structures\n * deepEqual(\n * { user: { name: 'Alice', tags: ['admin'] } },\n * { user: { name: 'Alice', tags: ['admin'] } }\n * ) // true\n *\n * // Dates\n * deepEqual(new Date('2024-01-01'), new Date('2024-01-01')) // true\n * deepEqual(new Date('2024-01-01'), new Date('2024-01-02')) // false\n *\n * // RegExp\n * deepEqual(/test/gi, /test/gi) // true\n * deepEqual(/test/g, /test/i) // false\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect if form data changed\n * const originalData = {\n * name: 'John Doe',\n * email: 'john@example.com',\n * preferences: { theme: 'dark', notifications: true }\n * }\n *\n * const currentData = {\n * name: 'John Doe',\n * email: 'john.doe@example.com', // Changed!\n * preferences: { theme: 'dark', notifications: true }\n * }\n *\n * const hasChanges = !deepEqual(originalData, currentData)\n * if (hasChanges) {\n * console.log('⚠️ You have unsaved changes')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Cache invalidation\n * const cache = new Map<string, { params: any; result: any }>()\n *\n * function cachedApiCall(params: any) {\n * const cacheKey = 'api-call'\n * const cached = cache.get(cacheKey)\n *\n * // Check if cached params match current params\n * if (cached && deepEqual(cached.params, params)) {\n * console.log('✅ Cache hit')\n * return cached.result\n * }\n *\n * console.log('❌ Cache miss - fetching')\n * const result = fetchData(params)\n * cache.set(cacheKey, { params, result })\n * return result\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: React shouldComponentUpdate optimization\n * class UserProfile extends React.Component {\n * shouldComponentUpdate(nextProps: any) {\n * // Only re-render if props actually changed\n * return !deepEqual(this.props, nextProps)\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Testing\n * import { deepEqual } from '@g10/ts-helpers'\n *\n * test('API returns expected user structure', async () => {\n * const response = await api.getUser(123)\n *\n * const expected = {\n * id: 123,\n * name: 'Alice',\n * roles: ['user', 'admin'],\n * metadata: { lastLogin: expect.any(Date) }\n * }\n *\n * // Deep comparison ignoring date instance\n * expect(deepEqual(\n * { ...response, metadata: { ...response.metadata, lastLogin: null } },\n * { ...expected, metadata: { ...expected.metadata, lastLogin: null } }\n * )).toBe(true)\n * })\n * ```\n *\n * @see {@link calculateDifferences} for finding specific differences between objects\n * @see {@link comparator} for lodash-based comparison (deprecated)\n * @see {@link https://github.com/epoberezkin/fast-deep-equal fast-deep-equal library}\n */\nexport const deepEqual = (data1: any, data2: any) => fastEqual(data1, data2)\n\n/**\n * Converts an object to a human-readable string representation\n *\n * Transforms JSON object to clean, readable text by removing braces, quotes, and\n * adding spacing. Useful for logging, debugging, UI displays, and error messages.\n *\n * Transformation:\n * 1. Stringify object to JSON\n * 2. Remove braces `{}` and quotes `\"`\n * 3. Replace commas with comma+space for readability\n *\n * @param data - Object to format (must be JSON-serializable)\n * @returns Human-readable string representation\n *\n * @example\n * ```typescript\n * // Simple object\n * formatToReadableString({ name: 'Alice', age: 25 })\n * // 'name: Alice, age: 25'\n *\n * // Multiple properties\n * formatToReadableString({ id: 1, status: 'active', verified: true })\n * // 'id: 1, status: active, verified: true'\n *\n * // Nested objects (flattened)\n * formatToReadableString({ user: { name: 'Bob' }, role: 'admin' })\n * // 'user: name: Bob, role: admin'\n *\n * // Empty object\n * formatToReadableString({})\n * // ''\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Log request parameters\n * function logApiRequest(endpoint: string, params: any) {\n * const paramsStr = formatToReadableString(params)\n * console.log(`API Request: ${endpoint} | Params: ${paramsStr}`)\n * }\n *\n * logApiRequest('/users', { page: 1, limit: 20, role: 'admin' })\n * // API Request: /users | Params: page: 1, limit: 20, role: admin\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Display validation errors\n * const errors = { email: 'Invalid format', password: 'Too short' }\n * const message = `Validation failed: ${formatToReadableString(errors)}`\n * console.log(message)\n * // Validation failed: email: Invalid format, password: Too short\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Format metadata for display\n * const metadata = {\n * author: 'John Doe',\n * created: '2024-01-01',\n * tags: ['javascript', 'typescript']\n * }\n *\n * const metadataDisplay = formatToReadableString(metadata)\n * // 'author: John Doe, created: 2024-01-01, tags: javascript, typescript'\n * ```\n *\n * @see {@link JSON.stringify} for full JSON serialization\n */\nexport const formatToReadableString = (data: { [key: string]: any }): string =>\n JSON.stringify(data).replace(/[{}\"]/g, '').replace(/,/g, ', ')\n\n/**\n * Extracts only top-level primitive properties from an object\n *\n * Filters out nested objects, arrays, and functions, returning only primitive values\n * (string, number, boolean, null, undefined, symbol). Useful for serialization,\n * API payloads, and database operations.\n *\n * Included types: string, number, boolean, null, undefined, symbol\n * Excluded types: object, array, function\n *\n * @param obj - Object from which to extract properties (null/undefined returns {})\n * @returns New object containing only primitive top-level properties\n *\n * @example\n * ```typescript\n * // Mixed types object\n * const user = {\n * id: 123,\n * name: 'Alice',\n * email: 'alice@example.com',\n * age: 25,\n * active: true,\n * metadata: { lastLogin: '2024-01-01' }, // Excluded (object)\n * roles: ['admin', 'user'], // Excluded (array)\n * save: () => {} // Excluded (function)\n * }\n *\n * getShallowProperties(user)\n * // { id: 123, name: 'Alice', email: 'alice@example.com', age: 25, active: true }\n *\n * // Only primitives\n * const config = { host: 'localhost', port: 5432, ssl: false }\n * getShallowProperties(config)\n * // { host: 'localhost', port: 5432, ssl: false } (unchanged)\n *\n * // Null/undefined values preserved\n * const partial = { a: 1, b: null, c: undefined, d: { nested: true } }\n * getShallowProperties(partial)\n * // { a: 1, b: null, c: undefined }\n *\n * // Empty/null input\n * getShallowProperties({}) // {}\n * getShallowProperties(null) // {}\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Prepare data for SQL insert (exclude nested objects)\n * const formData = {\n * firstName: 'John',\n * lastName: 'Doe',\n * email: 'john@example.com',\n * age: 30,\n * address: { street: '123 Main St', city: 'NYC' }, // Excluded\n * preferences: { theme: 'dark' } // Excluded\n * }\n *\n * const insertData = getShallowProperties(formData)\n * // { firstName: 'John', lastName: 'Doe', email: 'john@example.com', age: 30 }\n *\n * // Now safe to insert into flat database table\n * await db.insert('users', insertData)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Extract searchable fields for indexing\n * const product = {\n * sku: 'ABC123',\n * name: 'Widget',\n * price: 29.99,\n * inStock: true,\n * category: { id: 1, name: 'Electronics' }, // Excluded\n * reviews: [{ rating: 5 }], // Excluded\n * images: ['img1.jpg', 'img2.jpg'] // Excluded\n * }\n *\n * const searchableFields = getShallowProperties(product)\n * // { sku: 'ABC123', name: 'Widget', price: 29.99, inStock: true }\n *\n * // Index only primitive fields for search\n * searchIndex.add(product.sku, searchableFields)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Extract flat properties for CSV export\n * const users = [\n * {\n * id: 1,\n * name: 'Alice',\n * email: 'alice@example.com',\n * profile: { bio: 'Developer' },\n * tags: ['admin']\n * },\n * {\n * id: 2,\n * name: 'Bob',\n * email: 'bob@example.com',\n * profile: { bio: 'Designer' },\n * tags: ['user']\n * }\n * ]\n *\n * const csvData = users.map(getShallowProperties)\n * // [\n * // { id: 1, name: 'Alice', email: 'alice@example.com' },\n * // { id: 2, name: 'Bob', email: 'bob@example.com' }\n * // ]\n * // Now safe to convert to CSV\n * ```\n *\n * @see {@link calculateDifferences} for comparing objects\n * @see {@link deepEqual} for deep comparison including nested objects\n */\nexport const getShallowProperties = (obj: any): any => {\n if (!obj) return {}\n const topLevelProps: any = {}\n for (const prop in obj) {\n if (Object.hasOwnProperty.call(obj, prop)) {\n const value = obj[prop]\n const type = typeof value\n // Include primitives: string, number, boolean, undefined, symbol, and null\n if ((type !== 'object' && type !== 'function') || value === null) {\n topLevelProps[prop] = value\n }\n }\n }\n return topLevelProps\n}\n\n/**\n * Calculates differences between two objects\n *\n * Compares two objects and returns only the properties that differ. Useful for\n * change tracking, audit logs, delta updates, and optimistic UI updates.\n *\n * Special features:\n * - Date comparison: Compares dates ignoring milliseconds (tolerance-based)\n * - Shallow comparison: Only checks top-level properties\n * - One-way diff: Returns changed properties from newObj (not deletions)\n *\n * @param oldObj - Original object to compare against (baseline)\n * @param newObj - New object to compare (current state)\n * @returns Object containing only properties that changed in newObj\n *\n * @example\n * ```typescript\n * // Simple property changes\n * const old = { name: 'Alice', age: 25, city: 'NYC' }\n * const updated = { name: 'Alice', age: 26, city: 'NYC' }\n *\n * calculateDifferences(old, updated)\n * // { age: 26 } - only changed property\n *\n * // Multiple changes\n * const old2 = { a: 1, b: 2, c: 3 }\n * const new2 = { a: 1, b: 999, c: 3 }\n * calculateDifferences(old2, new2)\n * // { b: 999 }\n *\n * // No changes\n * const old3 = { x: 10 }\n * const new3 = { x: 10 }\n * calculateDifferences(old3, new3)\n * // {} - empty object\n *\n * // Date comparison (ignores milliseconds)\n * const oldDate = { timestamp: new Date('2024-01-01T10:00:00.123Z') }\n * const newDate = { timestamp: new Date('2024-01-01T10:00:00.456Z') }\n * calculateDifferences(oldDate, newDate)\n * // {} - dates considered equal (same second)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Track form changes for audit log\n * const originalUser = {\n * name: 'John Doe',\n * email: 'john@example.com',\n * role: 'user',\n * lastLogin: new Date('2024-01-01')\n * }\n *\n * const updatedUser = {\n * name: 'John Doe',\n * email: 'john.doe@company.com', // Changed\n * role: 'admin', // Changed\n * lastLogin: new Date('2024-01-01')\n * }\n *\n * const changes = calculateDifferences(originalUser, updatedUser)\n * console.log('User changes:', changes)\n * // { email: 'john.doe@company.com', role: 'admin' }\n *\n * // Save to audit log\n * auditLog.push({\n * userId: user.id,\n * timestamp: new Date(),\n * changes: changes\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Optimistic UI updates (send only changed fields)\n * function updateUserProfile(userId: string, formData: any) {\n * const originalData = getCurrentUserData(userId)\n *\n * // Only send changed fields to API\n * const delta = calculateDifferences(originalData, formData)\n *\n * if (Object.keys(delta).length === 0) {\n * console.log('✅ No changes to save')\n * return\n * }\n *\n * // Send PATCH request with only changed fields\n * return api.patch(`/users/${userId}`, delta)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Configuration change detection\n * const previousConfig = {\n * database: { host: 'localhost', port: 5432 },\n * cache: { ttl: 3600 },\n * features: { darkMode: true }\n * }\n *\n * const newConfig = {\n * database: { host: 'prod-db.example.com', port: 5432 },\n * cache: { ttl: 7200 },\n * features: { darkMode: true }\n * }\n *\n * const configChanges = calculateDifferences(previousConfig, newConfig)\n * // {\n * // database: { host: 'prod-db.example.com', port: 5432 },\n * // cache: { ttl: 7200 }\n * // }\n *\n * // Note: Returns entire nested object if any property changed\n * if (configChanges.database) {\n * console.log('⚠️ Database configuration changed - restart required')\n * }\n * ```\n *\n * @see {@link deepEqual} for full equality check\n * @see {@link getShallowProperties} for extracting only primitive properties\n */\nexport const calculateDifferences = (oldObj: any, newObj: any): any => {\n return transform(\n newObj,\n (result, value, key) => {\n const oldValue = oldObj[key]\n // If both values are dates, compare them ignoring milliseconds\n if (isDateTime(value) && isDateTime(oldValue)) {\n if (!areDatesEqualWithTolerance(toDate(value), toDate(oldValue))) {\n result[key] = value\n }\n } else if (!isEqual(value, oldValue)) {\n result[key] = value\n }\n },\n {}\n )\n}\n\n/**\n * Generates CRC32 hash from various input types\n *\n * Creates a 32-bit cyclic redundancy check (CRC32) hash as hexadecimal string.\n * Fast, deterministic fingerprinting for data integrity, caching, and change detection.\n *\n * Supported types:\n * - String: Direct hash\n * - Buffer/Uint8Array/ArrayBuffer: Binary hash\n * - Number: Converts to string then hash\n * - Boolean: 'true'/'false' then hash\n * - Object/Array: JSON.stringify then hash\n * - null/undefined: Hash of '-'\n *\n * Use cases: Content fingerprinting, ETags, cache keys, data deduplication\n *\n * ⚠️ NOTE: CRC32 is NOT cryptographically secure. Use for checksums, not security.\n *\n * @param str - Input data of any type (string, Buffer, object, array, primitive)\n * @returns CRC32 hash as hexadecimal string (8 characters)\n *\n * @example\n * ```typescript\n * // String inputs\n * generateCrcHash('hello') // '3610a686'\n * generateCrcHash('Hello') // 'f7d18982' (case-sensitive)\n * generateCrcHash('') // '0'\n *\n * // Numbers\n * generateCrcHash(123) // '884863d2' (hashes '123')\n * generateCrcHash(0) // 'f4dbdf21'\n *\n * // Booleans\n * generateCrcHash(true) // 'cc2c5c10' (hashes 'true')\n * generateCrcHash(false) // 'cc0c5c10' (hashes 'false')\n *\n * // Objects (deterministic)\n * generateCrcHash({ a: 1, b: 2 }) // Same hash for same object\n * generateCrcHash({ b: 2, a: 1 }) // Different hash (key order matters)\n *\n * // Arrays\n * generateCrcHash([1, 2, 3]) // Consistent hash\n *\n * // null/undefined\n * generateCrcHash(null) // '4e08bfb4' (hashes '-')\n * generateCrcHash(undefined) // '4e08bfb4' (hashes '-')\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate ETag for HTTP caching\n * function generateETag(content: string): string {\n * const hash = generateCrcHash(content)\n * return `\"${hash}\"`\n * }\n *\n * const html = '<html><body>Hello World</body></html>'\n * const etag = generateETag(html)\n * // \"a3c2f1b8\"\n *\n * // Client sends: If-None-Match: \"a3c2f1b8\"\n * // Server compares ETags, returns 304 Not Modified if match\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Content-based cache key\n * const cache = new Map<string, any>()\n *\n * function cacheApiResponse(params: any, response: any) {\n * const cacheKey = generateCrcHash(JSON.stringify(params))\n * cache.set(cacheKey, response)\n * }\n *\n * function getCachedResponse(params: any) {\n * const cacheKey = generateCrcHash(JSON.stringify(params))\n * return cache.get(cacheKey)\n * }\n *\n * // Same params = same hash = cache hit\n * cacheApiResponse({ userId: 123, page: 1 }, { data: [...] })\n * const cached = getCachedResponse({ userId: 123, page: 1 })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect duplicate content\n * const seen = new Set<string>()\n *\n * function isDuplicate(content: string): boolean {\n * const hash = generateCrcHash(content)\n * if (seen.has(hash)) {\n * return true\n * }\n * seen.add(hash)\n * return false\n * }\n *\n * isDuplicate('Hello') // false (first time)\n * isDuplicate('World') // false\n * isDuplicate('Hello') // true (duplicate!)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: File versioning/fingerprinting\n * const fileContents = [\n * { path: 'app.js', content: 'console.log(\"v1\")' },\n * { path: 'style.css', content: 'body { color: red; }' }\n * ]\n *\n * const manifest = fileContents.map(file => ({\n * path: file.path,\n * hash: generateCrcHash(file.content),\n * url: `${file.path}?v=${generateCrcHash(file.content)}`\n * }))\n *\n * // [\n * // { path: 'app.js', hash: 'a3c2f1b8', url: 'app.js?v=a3c2f1b8' },\n * // { path: 'style.css', hash: 'b4d3e2c1', url: 'style.css?v=b4d3e2c1' }\n * // ]\n * // Cache-busting URLs change only when content changes\n * ```\n *\n * @see {@link deepEqual} for comparing objects for equality\n * @see {@link https://en.wikipedia.org/wiki/Cyclic_redundancy_check CRC32 Algorithm}\n */\nexport const generateCrcHash = (str: string | Buffer | Uint8Array | any): string => {\n if (isNil(str)) return crc32('-').toString(16)\n if (isString(str)) return crc32(str).toString(16)\n if (isBuffer(str)) return crc32(str).toString(16)\n if (isArrayBuffer(str)) return crc32(str).toString(16)\n if (isBoolean(str)) return crc32(str ? 'true' : 'false').toString(16)\n if (isNumber(str)) return crc32(str.toString()).toString(16)\n if (isArray(str) || isObject(str)) return generateCrcHash(JSON.stringify(str))\n return crc32(str || '').toString(16)\n}\n\n/**\n * Verifies if two variables have the same type\n *\n * Performs strict type comparison with special handling for arrays, typed arrays,\n * plain objects, and primitives. Uses runtime type checking for accurate validation.\n *\n * Type detection hierarchy:\n * 1. Arrays: Standard Array.isArray() check\n * 2. Typed Arrays: Int8Array, Uint8Array, Float32Array, etc. (checks exact typed array class)\n * 3. Plain Objects: Object literals (not class instances or built-in objects)\n * 4. Primitives: typeof comparison (string, number, boolean, undefined, symbol)\n *\n * Special features:\n * - Differentiates between arrays and typed arrays\n * - Typed array class matching (Int8Array ≠ Uint8Array)\n * - Plain object vs class instance detection\n * - null/undefined handling\n *\n * @param sourceTarget - First value to check type\n * @param destinationTarget - Second value to check type\n * @returns True if both values have the same type, false otherwise\n *\n * @example\n * ```typescript\n * // Basic types - Primitives\n * hasSameType('hello', 'world') // true (both string)\n * hasSameType(42, 100) // true (both number)\n * hasSameType(true, false) // true (both boolean)\n * hasSameType('hello', 42) // false (string vs number)\n * hasSameType(null, undefined) // false (different types)\n * ```\n *\n * @example\n * ```typescript\n * // Arrays and objects\n * hasSameType([1, 2, 3], [4, 5]) // true (both arrays)\n * hasSameType({ a: 1 }, { b: 2 }) // true (both plain objects)\n * hasSameType([1, 2], { a: 1 }) // false (array vs object)\n * hasSameType([], {}) // false (array vs object)\n * ```\n *\n * @example\n * ```typescript\n * // Typed arrays - Strict class matching\n * const int8 = new Int8Array([1, 2, 3])\n * const int8_2 = new Int8Array([4, 5])\n * const uint8 = new Uint8Array([1, 2, 3])\n * const float32 = new Float32Array([1.5, 2.5])\n *\n * hasSameType(int8, int8_2) // true (both Int8Array)\n * hasSameType(int8, uint8) // false (Int8Array vs Uint8Array)\n * hasSameType(uint8, float32) // false (Uint8Array vs Float32Array)\n * hasSameType(int8, [1, 2, 3]) // false (typed array vs regular array)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Type-safe data merging\n * function safeMerge<T>(source: T, updates: any): T | null {\n * if (!hasSameType(source, updates)) {\n * console.error('❌ Type mismatch: cannot merge incompatible types')\n * return null\n * }\n *\n * if (Array.isArray(source)) {\n * return [...source, ...updates] as T\n * }\n *\n * if (typeof source === 'object' && source !== null) {\n * return { ...source, ...updates }\n * }\n *\n * return updates // Replace primitive values\n * }\n *\n * // Valid merges\n * const user = { name: 'John', age: 30 }\n * const updated = safeMerge(user, { age: 31, city: 'NYC' })\n * // { name: 'John', age: 31, city: 'NYC' }\n *\n * // Type mismatch prevented\n * const invalid = safeMerge(user, [1, 2, 3])\n * // null (with error logged)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: API response validation\n * function validateResponseShape(expected: any, actual: any): boolean {\n * // Check if response has the same structure\n * if (!hasSameType(expected, actual)) {\n * console.error('Invalid response type:', {\n * expected: typeof expected,\n * actual: typeof actual\n * })\n * return false\n * }\n *\n * // Additional validation for objects/arrays\n * if (typeof expected === 'object' && expected !== null) {\n * for (const key of Object.keys(expected)) {\n * if (!hasSameType(expected[key], actual[key])) {\n * console.error(`Type mismatch at key \"${key}\"`)\n * return false\n * }\n * }\n * }\n *\n * return true\n * }\n *\n * const expectedUser = {\n * id: 0,\n * name: '',\n * active: false,\n * tags: [] as string[]\n * }\n *\n * const validResponse = {\n * id: 123,\n * name: 'Alice',\n * active: true,\n * tags: ['admin', 'verified']\n * }\n *\n * validateResponseShape(expectedUser, validResponse) // true\n *\n * const invalidResponse = {\n * id: '123', // ❌ string instead of number\n * name: 'Alice',\n * active: true,\n * tags: ['admin']\n * }\n *\n * validateResponseShape(expectedUser, invalidResponse) // false\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Buffer/TypedArray validation before processing\n * function processImageBuffer(buffer: Uint8Array | Uint8ClampedArray): void {\n * const validBufferTypes = [\n * new Uint8Array(0),\n * new Uint8ClampedArray(0)\n * ]\n *\n * const isValidType = validBufferTypes.some(validType =>\n * hasSameType(buffer, validType)\n * )\n *\n * if (!isValidType) {\n * throw new TypeError('Expected Uint8Array or Uint8ClampedArray for image data')\n * }\n *\n * // Safe to process buffer\n * console.log(`Processing ${buffer.length} bytes of image data`)\n * }\n *\n * // Valid buffers\n * const imageData = new Uint8ClampedArray([255, 0, 0, 255]) // RGBA pixel\n * processImageBuffer(imageData) // ✅ Works\n *\n * // Invalid buffer type\n * const float32Buffer = new Float32Array([1.0, 0.5])\n * processImageBuffer(float32Buffer) // ❌ TypeError\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * hasSameType(null, null) // true (both null)\n * hasSameType(undefined, undefined) // true (both undefined)\n * hasSameType(null, undefined) // false (different types)\n * hasSameType(NaN, NaN) // true (both number)\n * hasSameType(Infinity, -Infinity) // true (both number)\n *\n * // Class instances vs plain objects\n * class User { name = 'John' }\n * const userInstance = new User()\n * const plainUser = { name: 'John' }\n * hasSameType(userInstance, plainUser) // false (class instance vs plain object)\n *\n * // Functions\n * const fn1 = () => {}\n * const fn2 = function() {}\n * hasSameType(fn1, fn2) // true (both functions)\n * ```\n *\n * @see {@link deepEqual} for value comparison (not just type)\n * @see {@link isArray} for array checking\n * @see {@link isPlainObject} for plain object detection\n */\nexport const hasSameType = (sourceTarget: any, destinationTarget: any) => {\n if (isArray(sourceTarget) && isArray(destinationTarget)) return true\n if (isArray(sourceTarget) !== isArray(destinationTarget)) return false\n if (isTypedArray(sourceTarget) && isTypedArray(destinationTarget)) {\n if (\n Object.prototype.toString.call(sourceTarget) ===\n Object.prototype.toString.call(destinationTarget)\n )\n return true\n else return false\n }\n if (isTypedArray(sourceTarget) !== isTypedArray(destinationTarget)) return false\n if (isPlainObject(sourceTarget) && isPlainObject(destinationTarget)) return true\n\n // Check if one is object and the other is not\n if (isPlainObject(sourceTarget) !== isPlainObject(destinationTarget)) return false\n\n return typeof sourceTarget === typeof destinationTarget\n}\n\n/**\n * Updates array elements that match search criteria\n *\n * Finds all elements matching the search criteria and merges update object into them.\n * Mutates the original array. Useful for batch updates on filtered data.\n *\n * Algorithm:\n * 1. Filter array to find elements matching objSearch\n * 2. For each match, merge objUpd properties using Object.assign\n * 3. Return the mutated array\n *\n * @param data - Array to update (will be mutated)\n * @param objUpd - Object with properties to merge into matching elements\n * @param objSearch - Object with search criteria (all properties must match)\n * @returns The mutated array with updated elements\n *\n * @example\n * ```typescript\n * // Update all users with role 'user' to 'member'\n * const users = [\n * { id: 1, name: 'Alice', role: 'user', active: true },\n * { id: 2, name: 'Bob', role: 'admin', active: true },\n * { id: 3, name: 'Charlie', role: 'user', active: false }\n * ]\n *\n * updateArrayElementsBy(users, { role: 'member' }, { role: 'user' })\n * // users is now:\n * // [\n * // { id: 1, name: 'Alice', role: 'member', active: true },\n * // { id: 2, name: 'Bob', role: 'admin', active: true },\n * // { id: 3, name: 'Charlie', role: 'member', active: false }\n * // ]\n *\n * // Update multiple properties\n * const products = [\n * { sku: 'A1', status: 'draft', published: false },\n * { sku: 'A2', status: 'draft', published: false },\n * { sku: 'B1', status: 'active', published: true }\n * ]\n *\n * updateArrayElementsBy(\n * products,\n * { status: 'active', published: true },\n * { status: 'draft' }\n * )\n * // All draft products now active and published\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Bulk activate pending users\n * const pendingUsers = [\n * { email: 'user1@example.com', status: 'pending', verified: false },\n * { email: 'user2@example.com', status: 'pending', verified: false },\n * { email: 'user3@example.com', status: 'active', verified: true }\n * ]\n *\n * // Activate all pending users\n * updateArrayElementsBy(\n * pendingUsers,\n * { status: 'active', verified: true, activatedAt: new Date() },\n * { status: 'pending' }\n * )\n *\n * console.log(pendingUsers.filter(u => u.status === 'active').length)\n * // 3 (all users now active)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Mark completed tasks as archived\n * const tasks = [\n * { id: 1, title: 'Task 1', completed: true, archived: false },\n * { id: 2, title: 'Task 2', completed: false, archived: false },\n * { id: 3, title: 'Task 3', completed: true, archived: false }\n * ]\n *\n * updateArrayElementsBy(\n * tasks,\n * { archived: true, archivedAt: new Date() },\n * { completed: true }\n * )\n *\n * const archivedCount = tasks.filter(t => t.archived).length\n * console.log(`Archived ${archivedCount} completed tasks`)\n * ```\n *\n * @see {@link updateArrayElementById} for updating single element by ID\n * @see {@link deleteArrayElementsBy} for deleting elements by criteria\n */\nexport const updateArrayElementsBy = (data: any[], objUpd: any, objSearch: any) => {\n nativeFilter(data, objSearch).forEach(element => nativeAssign(element, objUpd))\n return data\n}\n\n/**\n * Updates a single array element by its ID field\n *\n * Finds element by matching ID field value and replaces entire element with new object.\n * Mutates the original array. Use for updating single records by primary key.\n *\n * Algorithm:\n * 1. Find index of element where element[idField] === objUpd[idField]\n * 2. If found, replace entire element with objUpd\n * 3. If not found, array remains unchanged\n *\n * @param data - Array to update (will be mutated)\n * @param objUpd - New object to replace the found element (must contain idField)\n * @param idField - Name of field to use as identifier (default: 'id')\n * @returns void (modifies array in-place)\n *\n * @example\n * ```typescript\n * // Update user by ID\n * const users = [\n * { id: 1, name: 'Alice', email: 'alice@example.com' },\n * { id: 2, name: 'Bob', email: 'bob@example.com' },\n * { id: 3, name: 'Charlie', email: 'charlie@example.com' }\n * ]\n *\n * updateArrayElementById(\n * users,\n * { id: 2, name: 'Robert', email: 'robert@example.com', verified: true },\n * 'id'\n * )\n * // users[1] is now: { id: 2, name: 'Robert', email: 'robert@example.com', verified: true }\n *\n * // ID not found - no change\n * updateArrayElementById(users, { id: 999, name: 'Unknown' }, 'id')\n * // users array unchanged\n *\n * // Custom ID field\n * const products = [\n * { sku: 'ABC123', name: 'Widget', price: 10 },\n * { sku: 'DEF456', name: 'Gadget', price: 20 }\n * ]\n *\n * updateArrayElementById(\n * products,\n * { sku: 'ABC123', name: 'Super Widget', price: 15 },\n * 'sku'\n * )\n * // products[0] is now: { sku: 'ABC123', name: 'Super Widget', price: 15 }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Update cached user after API response\n * const userCache = [\n * { id: 1, name: 'Alice', role: 'user' },\n * { id: 2, name: 'Bob', role: 'admin' },\n * ]\n *\n * async function updateUser(userId: number, updates: any) {\n * // API call\n * const response = await api.patch(`/users/${userId}`, updates)\n *\n * // Update local cache with full response\n * updateArrayElementById(userCache, response.data, 'id')\n *\n * console.log('✅ Cache updated')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Replace product in shopping cart\n * const cart = [\n * { productId: 'P1', name: 'Laptop', qty: 1, price: 1000 },\n * { productId: 'P2', name: 'Mouse', qty: 2, price: 25 }\n * ]\n *\n * function updateCartItem(updatedItem: any) {\n * updateArrayElementById(cart, updatedItem, 'productId')\n * recalculateTotal()\n * }\n *\n * // User changes laptop quantity\n * updateCartItem({ productId: 'P1', name: 'Laptop', qty: 2, price: 1000 })\n * ```\n *\n * @see {@link updateArrayElementsBy} for updating multiple elements by criteria\n * @see {@link deleteArrayElementsBy} for deleting elements\n */\nexport const updateArrayElementById = (data: any[], objUpd: any, idField: string) => {\n const index = data.findIndex(x => x[idField] === objUpd[idField])\n if (index !== -1) data.splice(index, 1, objUpd)\n}\n\n/**\n * Removes array elements that match search criteria\n *\n * Filters out elements matching all properties in the search object.\n * Mutates the original array. Useful for batch deletions based on criteria.\n *\n * Algorithm:\n * 1. Pick properties from each element matching objSearch keys\n * 2. Deep compare picked properties with objSearch\n * 3. Remove element if all properties match\n * 4. Return the mutated array\n *\n * @param data - Array to modify (will be mutated)\n * @param objSearch - Object with search criteria (all properties must match for deletion)\n * @returns The mutated array with matching elements removed\n *\n * @example\n * ```typescript\n * // Delete users with role 'guest'\n * const users = [\n * { id: 1, name: 'Alice', role: 'admin' },\n * { id: 2, name: 'Bob', role: 'guest' },\n * { id: 3, name: 'Charlie', role: 'guest' },\n * { id: 4, name: 'Dave', role: 'user' }\n * ]\n *\n * deleteArrayElementsBy(users, { role: 'guest' })\n * // users is now: [\n * // { id: 1, name: 'Alice', role: 'admin' },\n * // { id: 4, name: 'Dave', role: 'user' }\n * // ]\n *\n * // Multiple criteria (AND condition)\n * const tasks = [\n * { id: 1, status: 'done', archived: true },\n * { id: 2, status: 'done', archived: false },\n * { id: 3, status: 'pending', archived: false }\n * ]\n *\n * deleteArrayElementsBy(tasks, { status: 'done', archived: true })\n * // Removes only tasks that are BOTH done AND archived\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Clean up expired sessions\n * const sessions = [\n * { sessionId: 'abc', userId: 1, expired: false },\n * { sessionId: 'def', userId: 2, expired: true },\n * { sessionId: 'ghi', userId: 3, expired: true },\n * { sessionId: 'jkl', userId: 4, expired: false }\n * ]\n *\n * // Remove all expired sessions\n * deleteArrayElementsBy(sessions, { expired: true })\n *\n * console.log(`Active sessions: ${sessions.length}`)\n * // Active sessions: 2\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Remove cancelled orders from pending list\n * const orders = [\n * { orderId: 'O1', status: 'pending', cancelled: false },\n * { orderId: 'O2', status: 'pending', cancelled: true },\n * { orderId: 'O3', status: 'shipped', cancelled: false },\n * { orderId: 'O4', status: 'pending', cancelled: true }\n * ]\n *\n * // Clean up cancelled pending orders\n * deleteArrayElementsBy(orders, { status: 'pending', cancelled: true })\n *\n * // orders now only has valid pending and shipped orders\n * console.log(orders.length) // 2\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Clear failed upload queue\n * const uploadQueue = [\n * { fileId: 'F1', status: 'uploading', retries: 0 },\n * { fileId: 'F2', status: 'failed', retries: 3 },\n * { fileId: 'F3', status: 'failed', retries: 3 },\n * { fileId: 'F4', status: 'completed', retries: 0 }\n * ]\n *\n * // Remove permanently failed uploads (max retries reached)\n * deleteArrayElementsBy(uploadQueue, { status: 'failed', retries: 3 })\n *\n * console.log(`Remaining in queue: ${uploadQueue.length}`)\n * // Remaining in queue: 2 (uploading + completed)\n * ```\n *\n * @see {@link updateArrayElementsBy} for updating elements by criteria\n * @see {@link updateArrayElementById} for updating single element by ID\n */\nexport const deleteArrayElementsBy = (data: any[], objSearch: any) => {\n nativeRemove(data, x => deepEqual(nativePick(x, Object.keys(objSearch) as any), objSearch))\n return data\n}\n\n/**\n * Sets a value at a deep path in an object using dot notation\n *\n * Creates intermediate objects/arrays as needed. Supports nested paths\n * and array indices. Mutates the original object.\n *\n * @param obj - Object to modify (will be mutated)\n * @param path - Dot-notation path (e.g., 'database.connection.timeout')\n * @param value - Value to set at the path\n * @returns The modified object (same reference as input)\n *\n * @example\n * ```typescript\n * // Simple nested path\n * const config = {}\n * setDeepValue(config, 'database.host', 'localhost')\n * // config = { database: { host: 'localhost' } }\n *\n * // Multi-level nesting\n * const obj = {}\n * setDeepValue(obj, 'app.server.port', 3000)\n * // obj = { app: { server: { port: 3000 } } }\n *\n * // Array indices\n * const data = { users: [] }\n * setDeepValue(data, 'users.0.name', 'Alice')\n * // data = { users: [{ name: 'Alice' }] }\n *\n * // Overwriting existing values\n * const settings = { database: { host: 'old' } }\n * setDeepValue(settings, 'database.host', 'new')\n * // settings = { database: { host: 'new' } }\n *\n * // Complex paths\n * const complex = {}\n * setDeepValue(complex, 'features.authentication.oauth.providers.0', 'google')\n * // complex = { features: { authentication: { oauth: { providers: ['google'] } } } }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Dynamic configuration\n * const config = {}\n * const envVars = {\n * 'DATABASE_HOST': 'localhost',\n * 'DATABASE_PORT': '5432',\n * 'CACHE_TTL': '3600'\n * }\n *\n * // Convert flat env vars to nested config\n * setDeepValue(config, 'database.host', envVars.DATABASE_HOST)\n * setDeepValue(config, 'database.port', parseInt(envVars.DATABASE_PORT))\n * setDeepValue(config, 'cache.ttl', parseInt(envVars.CACHE_TTL))\n * // config = {\n * // database: { host: 'localhost', port: 5432 },\n * // cache: { ttl: 3600 }\n * // }\n * ```\n */\nexport function setDeepValue<T = any>(obj: T, path: string, value: any): T {\n if (!obj || typeof obj !== 'object') {\n throw new TypeError('setDeepValue: target must be an object')\n }\n\n if (!path || typeof path !== 'string') {\n throw new TypeError('setDeepValue: path must be a non-empty string')\n }\n\n const keys = path.split('.')\n let current: any = obj\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n const nextKey = keys[i + 1]\n\n // Determine if next level should be an array or object\n const isNextArray = /^\\d+$/.test(nextKey)\n\n // Create intermediate level if it doesn't exist\n if (!(key in current) || typeof current[key] !== 'object') {\n current[key] = isNextArray ? [] : {}\n }\n\n current = current[key]\n }\n\n // Set the final value\n const lastKey = keys[keys.length - 1]\n current[lastKey] = value\n\n return obj\n}\n\n/**\n * Gets a value at a deep path in an object using dot notation\n *\n * Safely retrieves values from nested objects/arrays. Returns undefined\n * or a default value if path doesn't exist.\n *\n * @param obj - Object to read from\n * @param path - Dot-notation path (e.g., 'database.connection.timeout')\n * @param defaultValue - Value to return if path doesn't exist (default: undefined)\n * @returns Value at the path, or defaultValue if not found\n *\n * @example\n * ```typescript\n * // Simple nested access\n * const config = { database: { host: 'localhost' } }\n * getDeepValue(config, 'database.host') // 'localhost'\n *\n * // Non-existent path returns undefined\n * getDeepValue(config, 'database.port') // undefined\n *\n * // With default value\n * getDeepValue(config, 'database.port', 5432) // 5432\n *\n * // Array access\n * const data = { users: [{ name: 'Alice' }, { name: 'Bob' }] }\n * getDeepValue(data, 'users.0.name') // 'Alice'\n * getDeepValue(data, 'users.1.name') // 'Bob'\n *\n * // Deep paths\n * const app = { features: { auth: { enabled: true } } }\n * getDeepValue(app, 'features.auth.enabled') // true\n * getDeepValue(app, 'features.payments.enabled', false) // false (default)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Safe config access\n * const config = {\n * database: { host: 'localhost' },\n * cache: { ttl: 3600 }\n * }\n *\n * const dbHost = getDeepValue(config, 'database.host', '127.0.0.1')\n * const dbPort = getDeepValue(config, 'database.port', 5432)\n * const cacheTtl = getDeepValue(config, 'cache.ttl', 1800)\n * const redisHost = getDeepValue(config, 'redis.host', 'localhost')\n *\n * // All values are safely retrieved with fallbacks\n * ```\n */\nexport function getDeepValue<T = any>(obj: any, path: string, defaultValue?: T): T | undefined {\n if (!obj || typeof obj !== 'object') {\n return defaultValue\n }\n\n if (!path || typeof path !== 'string') {\n return defaultValue\n }\n\n const keys = path.split('.')\n let current = obj\n\n for (const key of keys) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return defaultValue\n }\n\n if (!(key in current)) {\n return defaultValue\n }\n\n current = current[key]\n }\n\n return current !== undefined ? current : defaultValue\n}\n","/**\n * Date manipulation and formatting utilities\n * Consolidated from specialized/date module\n */\n\nimport dayjs from 'dayjs'\nimport utc from 'dayjs/plugin/utc.js'\nimport relativeTime from 'dayjs/plugin/relativeTime.js'\nimport weekOfYearPlugin from 'dayjs/plugin/weekOfYear.js'\nimport customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport isSameOrAfter from 'dayjs/plugin/isSameOrAfter.js'\nimport isSameOrBefore from 'dayjs/plugin/isSameOrBefore.js'\nimport weekday from 'dayjs/plugin/weekday.js'\nimport localeData from 'dayjs/plugin/localeData.js'\nimport localizedFormat from 'dayjs/plugin/localizedFormat.js'\nimport 'dayjs/locale/es.js'\nimport * as dateValidator from 'iso-datestring-validator'\nconst { isValidDate, isValidISODateString } = dateValidator\n\n// Configure dayjs plugins\ndayjs.extend(utc)\ndayjs.extend(relativeTime)\ndayjs.extend(weekOfYearPlugin)\ndayjs.extend(customParseFormat)\ndayjs.extend(isSameOrAfter)\ndayjs.extend(isSameOrBefore)\ndayjs.extend(weekday)\ndayjs.extend(localeData)\ndayjs.extend(localizedFormat)\n\n// Set default locale to Spanish\ndayjs.locale('es')\n\n/**\n * Formats current date with specified format\n */\nexport const formatNow = (formatStr = 'DD/MM/YYYY'): string => dayjs().format(formatStr)\n\n/**\n * Formats date with specified format string (Spanish locale by default)\n *\n * Flexible date formatter with special support for week-of-year formats.\n * Uses dayjs Spanish locale for month/day names.\n *\n * @param value - Date value to format (Date, string, timestamp, dayjs)\n * @param formatStr - Format string (default: 'DD/MM/YYYY' for Spanish dates)\n * @returns Formatted date string, empty string if value is null/undefined\n *\n * @example\n * ```typescript\n * const date = new Date('2024-03-15')\n *\n * format(date) // '15/03/2024' (Spanish default)\n * format(date, 'DD-MM-YYYY') // '15-03-2024'\n * format(date, 'YYYY/MM/DD') // '2024/03/15'\n * format(date, 'DD MMM YYYY') // '15 mar 2024' (Spanish month)\n * format(date, 'dddd, DD MMMM') // 'viernes, 15 marzo' (Spanish)\n * format(date, 'gg') // '11' (week of year)\n * format(date, 'gggg') // '2411' (year + week)\n * ```\n *\n * @see {@link longString} for localized long format\n * @see {@link formatNow} for current date formatting\n */\nexport const format = (value: any, formatStr = 'DD/MM/YYYY'): string => {\n if (!value) return ''\n if (formatStr.toLowerCase() === 'gg') return weekOfYear(value)\n else if (formatStr.toLowerCase() === 'gggg') return dayjs(value).format('YY') + weekOfYear(value)\n return dayjs(value).format(formatStr)\n}\n\n/**\n * Converts date to localized long string format (Spanish)\n *\n * Formats date as human-readable string with full month name in Spanish locale.\n * Uses dayjs 'LL' format: \"15 de marzo de 2024\"\n *\n * @param value - Date value to format (null returns empty string)\n * @returns Localized long format date string (e.g., \"15 de marzo de 2024\")\n *\n * @example\n * ```typescript\n * longString(new Date('2024-03-15')) // \"15 de marzo de 2024\"\n * longString('2024-12-25') // \"25 de diciembre de 2024\"\n * longString(null) // \"\"\n *\n * // Real-world: Document headers\n * const reportDate = longString(new Date())\n * console.log(`Informe generado el ${reportDate}`)\n * // \"Informe generado el 15 de marzo de 2024\"\n * ```\n *\n * @see {@link format} for custom format strings\n */\nexport const longString = (value: any = null) => {\n if (!value) return ''\n return dayjs(value).format('LL')\n}\n\n/**\n * Converts value to native JavaScript Date object\n */\nexport const toDate = (value: any, isUtc?: boolean) => {\n if (isUtc === undefined) return dayjs(value).toDate()\n return isUtc ? dayjs.utc(value).toDate() : dayjs(value).toDate()\n}\n\ntype DateStringFormat =\n | 'DD/MM/YYYY'\n | 'YYYY-MM-DD'\n | 'MM/DD/YYYY'\n | 'YYYY/MM/DD'\n | 'DD-MM-YYYY'\n | 'MM-DD-YYYY'\n | 'YYYYMMDD'\n | 'DDMMYYYY'\n | 'MMDDYYYY'\n | 'YYYY.MM.DD'\n | 'DD.MM.YYYY'\n | 'MM.DD.YYYY'\n\n/**\n * Parses date string with specific format to native Date object\n *\n * Strict parser that validates format and creates Date from structured date strings.\n * Supports 12 common date formats with validation.\n *\n * @param dateString - Date string to parse\n * @param format - Expected format (DD/MM/YYYY, YYYY-MM-DD, etc.)\n * @returns Date object or null if invalid\n *\n * @example\n * ```typescript\n * toDateFromString('15/03/2024', 'DD/MM/YYYY') // Date object\n * toDateFromString('2024-03-15', 'YYYY-MM-DD') // Date object\n * toDateFromString('invalid', 'DD/MM/YYYY') // null\n * ```\n *\n * @see {@link format} for formatting dates\n */\nexport const toDateFromString = (dateString: string, format: DateStringFormat): Date | null => {\n const formatRegex: Record<string, RegExp> = {\n 'DD/MM/YYYY': /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/,\n 'YYYY-MM-DD': /^(\\d{4})-(\\d{2})-(\\d{2})$/,\n 'MM/DD/YYYY': /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/,\n 'YYYY/MM/DD': /^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/,\n 'DD-MM-YYYY': /^(\\d{2})-(\\d{2})-(\\d{4})$/,\n 'MM-DD-YYYY': /^(\\d{2})-(\\d{2})-(\\d{4})$/,\n YYYYMMDD: /^(\\d{4})(\\d{2})(\\d{2})$/,\n DDMMYYYY: /^(\\d{2})(\\d{2})(\\d{4})$/,\n MMDDYYYY: /^(\\d{2})(\\d{2})(\\d{4})$/,\n 'YYYY.MM.DD': /^(\\d{4})\\.(\\d{2})\\.(\\d{2})$/,\n 'DD.MM.YYYY': /^(\\d{2})\\.(\\d{2})\\.(\\d{4})$/,\n 'MM.DD.YYYY': /^(\\d{2})\\.(\\d{2})\\.(\\d{4})$/,\n }\n\n const regex = formatRegex[format]\n if (!regex) return null\n\n const match = dateString.match(regex)\n if (match) {\n let year: number, month: number, day: number\n\n if (format.startsWith('YYYY')) {\n year = parseInt(match[1], 10)\n month = parseInt(match[2], 10) - 1\n day = parseInt(match[3], 10)\n } else if (format.startsWith('DD')) {\n day = parseInt(match[1], 10)\n month = parseInt(match[2], 10) - 1\n year = parseInt(match[3], 10)\n } else if (format.startsWith('MM')) {\n month = parseInt(match[1], 10) - 1\n day = parseInt(match[2], 10)\n year = parseInt(match[3], 10)\n } else {\n return null\n }\n\n return new Date(year, month, day)\n }\n\n return null\n}\n\n/**\n * Returns current date\n */\nexport const now = () => dayjs().toDate()\n\n/**\n * Checks if date is considered \"new\" based on days threshold\n */\nexport const isNew = (value: any, daysnew = 1) =>\n dayjs().isSameOrBefore(dayjs(value).add(daysnew, 'days'))\n\n/**\n * Converts date to ISO 8601 string (YYYY-MM-DDTHH:mm:ss.sssZ)\n *\n * Standard ISO format for API communication and storage.\n *\n * @param value - Date to convert (null = now)\n * @param isUtc - Force UTC timezone (default: false, uses local)\n * @returns ISO 8601 formatted string\n *\n * @example\n * ```typescript\n * toISO() // \"2024-03-15T10:30:00.000+01:00\" (now, local time)\n * toISO(new Date('2024-03-15')) // \"2024-03-15T00:00:00.000+01:00\"\n * toISO(new Date('2024-03-15'), true) // \"2024-03-14T23:00:00.000Z\" (UTC)\n * ```\n */\nexport const toISO = (value: any = null, isUtc = false) => {\n if (!value) return dayjs().toISOString()\n return isUtc ? dayjs.utc(value).toISOString() : dayjs(value).toISOString()\n}\n\n/**\n * Returns relative time from now in Spanish (e.g., \"hace 2 horas\")\n *\n * @param value - Date to compare with now\n * @returns Relative time string in Spanish\n *\n * @example\n * ```typescript\n * const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000)\n * fromNow(twoHoursAgo) // \"hace 2 horas\"\n * ```\n */\nexport const fromNow = (value: any) => dayjs(value).fromNow()\n\n/**\n * Returns day of week (0-6, Sunday is 0)\n */\nexport const dayOfWeek = (value: any = null) => {\n if (!value) return dayjs().format('d')\n return dayjs(value).format('d')\n}\n\n/**\n * Returns week of year with zero padding\n */\nexport const weekOfYear = (value: any = null) => {\n if (!value) return dayjs().locale('es').week().toString().padStart(2, '0')\n return dayjs(value).locale('es').week().toString().padStart(2, '0')\n}\n\n/**\n * Calculates difference in days between two dates\n */\nexport const diffDays = (start: any, end: any = null, precise = false) => {\n const v2 = !end ? dayjs() : dayjs(end)\n return dayjs(start).diff(v2, 'days', precise)\n}\n\n/**\n * Calculates difference in business days (weekdays only, excludes weekends)\n *\n * Counts Mon-Fri between two dates, excluding Saturdays and Sundays.\n * Does NOT account for holidays.\n *\n * @param start - Start date\n * @param end - End date (null = now)\n * @param precise - Include fractional days (default: false)\n * @returns Number of business days (Mon-Fri)\n *\n * @example\n * ```typescript\n * // Monday to Friday (same week)\n * diffBusinessDays('2024-03-11', '2024-03-15') // 4 business days\n *\n * // Including weekend (skip Sat/Sun)\n * diffBusinessDays('2024-03-15', '2024-03-18') // 1 (Fri to Mon)\n *\n * // Real-world: SLA calculation\n * const ticketCreated = new Date('2024-03-11')\n * const businessDays = diffBusinessDays(ticketCreated)\n * if (businessDays > 5) {\n * console.log('⚠️ SLA violation: > 5 business days')\n * }\n * ```\n */\nexport const diffBusinessDays = (start: any, end: any = null, precise = false) => {\n let startDate = dayjs(start).startOf('day')\n let endDate = end ? dayjs(end).startOf('day') : dayjs().startOf('day')\n\n if (startDate.isAfter(endDate)) {\n ;[startDate, endDate] = [endDate, startDate]\n }\n\n let businessDays = 0\n let currentDate = startDate\n\n while (currentDate.isBefore(endDate)) {\n if (isWeekday(currentDate)) {\n businessDays++\n }\n currentDate = currentDate.add(1, 'day')\n }\n\n if (precise) {\n const fractionalDay = endDate.diff(currentDate, 'hours') / 24\n businessDays += fractionalDay\n }\n\n return businessDays\n}\n\n/**\n * Calculates difference in months between two dates\n */\nexport const diffMonths = (value: any, valueRefOrNow: any = null, precise = false) => {\n const v2 = !valueRefOrNow ? dayjs() : dayjs(valueRefOrNow)\n return dayjs(value).diff(v2, 'months', precise)\n}\n\n/**\n * Calculates difference in years between two dates\n */\nexport const diffYears = (value: any, valueRefOrNow: any = null, precise = false) => {\n const v2 = !valueRefOrNow ? dayjs() : dayjs(valueRefOrNow)\n return dayjs(value).diff(v2, 'years', precise)\n}\n\n/**\n * Calculates difference in milliseconds between two dates\n */\nexport const diffMilliSeconds = (value: any, valueRefOrNow: any = null) => {\n const v2 = !valueRefOrNow ? dayjs() : dayjs(valueRefOrNow)\n return dayjs(value).diff(v2, 'milliseconds', true)\n}\n\n/**\n * Adds days to a date\n */\nexport const addDays = (value: any, nDays: number = 1) => dayjs(value).add(nDays, 'days').toDate()\n\n/**\n * Adds seconds to a date\n */\nexport const addSeconds = (value: any, nSeconds: number = 1) =>\n dayjs(value).add(nSeconds, 'seconds').toDate()\n\n/**\n * Compares two dates with ± 2 seconds tolerance\n */\nexport const areDatesEqualWithTolerance = (date1: Date, date2: Date): boolean => {\n const tolerance = 2 * 1000 // 2 seconds in milliseconds\n return Math.abs(dayjs(date1).diff(dayjs(date2))) <= tolerance\n}\n\n/**\n * Adds days to current date\n */\nexport const addNowDays = (nDays: number = 1) => dayjs().add(nDays, 'days').toDate()\n\n/**\n * Adds seconds to current date\n */\nexport const addNowSeconds = (nSeconds: number = 60) => dayjs().add(nSeconds, 'seconds').toDate()\n\n/**\n * Adds months to a date\n */\nexport const addMonths = (value: any, nMonths: number = 1) =>\n dayjs(value).add(nMonths, 'months').toDate()\n\n/**\n * Adds months to current date\n */\nexport const addNowMonths = (nMonths: number = 1) => dayjs().add(nMonths, 'months').toDate()\n\n/**\n * Adds years to a date\n */\nexport const addYears = (value: any, nYears: number = 1) =>\n dayjs(value).add(nYears, 'years').toDate()\n\n/**\n * Adds years to current date\n */\nexport const addNowYears = (nYears: number = 1) => dayjs().add(nYears, 'years').toDate()\n\n/**\n * Converts Excel serial number to Date\n * JavaScript dates can be constructed by passing milliseconds since Unix epoch\n */\nexport const excelToDate = (value: any) => {\n try {\n const d: number = Number(value)\n if (d >= 18000 && d <= 300000) return new Date(Math.round((d - 25569) * 86400 * 1000))\n return null\n } catch (_err) {\n return null\n }\n}\n\n/**\n * Detects if a variable contains a valid date\n */\nexport const isDateTime = (value: any): boolean => {\n try {\n if (!value) return false\n if (typeof value === 'number') return false\n else if (typeof value === 'boolean') return false\n else if (\n typeof value === 'string' &&\n !isValidISODateString(value) &&\n !isValidDate(value) &&\n !isValidDate(value, '')\n )\n return false\n else if (typeof value === 'object' && !(value instanceof Date) && !dayjs.isDayjs(value))\n return false\n return dayjs(value).isValid()\n } catch (_err) {\n return false\n }\n}\n\n/**\n * Compares dates by day\n */\nexport const isEqualsDateTimeByDay = (value1: any, value2: any): boolean => {\n if (!isDateTime(value1)) return false\n if (!isDateTime(value2)) return false\n return dayjs(value1).isSame(dayjs(value2), 'day')\n}\n\n/**\n * Checks if a date has expired relative to current time\n */\nexport const isExpired = (value: any, valueRefOrNow: any = null): boolean => {\n const v2 = !valueRefOrNow ? dayjs() : dayjs(valueRefOrNow)\n if (isDateTime(value)) {\n return v2.isAfter(value)\n }\n return true\n}\n\n/**\n * Formats date for MySQL database\n */\nexport const formatForMysql = (fecha: Date | null) => {\n if (!fecha) return null\n fecha.setMinutes(fecha.getMinutes() - fecha.getTimezoneOffset())\n return fecha.toISOString().slice(0, 19).replace('T', ' ')\n}\n\n/**\n * Gets first workday of month\n */\nexport const getFirstWorkdayOfMonth = (month?: number) => {\n const monthToUse = month === undefined ? dayjs().month() : month\n let firstDay = dayjs().month(monthToUse).startOf('month')\n while (firstDay.day() === 0 || firstDay.day() === 6) {\n firstDay = firstDay.add(1, 'day')\n }\n return firstDay.toDate()\n}\n\n/**\n * Gets last workday of month\n */\nexport const getLastWorkdayOfMonth = (month?: number) => {\n const monthToUse = month === undefined ? dayjs().month() : month\n let lastDay = dayjs().month(monthToUse).endOf('month')\n while (lastDay.day() === 0 || lastDay.day() === 6) {\n lastDay = lastDay.subtract(1, 'day')\n }\n return lastDay.toDate()\n}\n\n/**\n * Gets first workday after adding specified months\n */\nexport const getFirstWorkdayAfterMonths = (initialDate: Date, n: number) => {\n const startDate = dayjs(initialDate)\n const monthsToAdd = n\n const targetDate = startDate.add(monthsToAdd, 'months')\n\n let firstWorkday = targetDate.startOf('month')\n while (firstWorkday.day() === 0 || firstWorkday.day() === 6) {\n firstWorkday = firstWorkday.add(1, 'day')\n }\n return firstWorkday.toDate()\n}\n\n/**\n * Gets first day of current year\n */\nexport const getFirstDayOfYear = () => dayjs().startOf('year').toDate()\n\n/**\n * Gets last day of current year\n */\nexport const getLastDayOfYear = () => dayjs().endOf('year').toDate()\n\n/**\n * Checks if date is a weekday (not Saturday or Sunday)\n */\nexport const isWeekday = (date: any) => {\n const d = dayjs(date)\n const dayOfWeek = d.day() // 0 = Sunday, 1 = Monday, ..., 6 = Saturday\n return dayOfWeek !== 0 && dayOfWeek !== 6 // Exclude Saturdays and Sundays\n}\n","/**\n * Mathematical calculations, statistics, and financial utilities\n * Consolidated from specialized/math module\n */\n\nimport * as lodash from 'lodash'\nconst { map, round, sumBy, get, meanBy, maxBy, some, minBy, uniq, size, sum, zipObject, groupBy } =\n lodash\nimport { roundToDecimals } from './number'\n\n/**\n * Mathematical operations configuration for data aggregation\n * @template T - The type of objects being processed\n * @example\n * ```ts\n * // Simple operations configuration\n * const ops: IMathOp = {\n * $sum: ['amount', 'quantity'],\n * $avg: ['price', 'rating'],\n * $count: ['name'],\n * $max: ['sales'],\n * $min: ['cost']\n * }\n *\n * // For sales data\n * const salesOps: IMathOp<SalesRecord> = {\n * $sum: ['revenue', 'units'],\n * $avg: ['unitPrice'],\n * $countUniq: ['customerId']\n * }\n * ```\n */\nexport interface IMathOp<T = any> {\n /** Calculate average of numeric fields */\n $avg?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n /** Count occurrences of string fields */\n $count?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends string\n ? K\n : never\n : never\n : never)[]\n /** Count unique values in fields */\n $countUniq?: (keyof T)[]\n /** Check if field exists (1/0) */\n $exist?: (keyof T)[]\n /** Find maximum value in numeric fields */\n $max?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n /** Find minimum value in numeric fields */\n $min?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n /** Sum numeric fields */\n $sum?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n /** Calculate trend slope for numeric fields */\n $trend?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n}\n\n/**\n * Calculates mathematical operations on an array of objects with optional grouping\n * Supports statistical operations like sum, average, count, etc. with grouping capability\n * @param operations - Mathematical operations to perform on data fields\n * @param pgroupBy - Array of field names to group by (empty array for no grouping)\n * @param inData - Input data array to process\n * @param appendOperationToField - Whether to append operation name to result field names\n * @returns Aggregated data with calculated values\n * @example\n * ```ts\n * // Sales data aggregation\n * const sales = [\n * { region: 'North', product: 'Laptop', amount: 1000, quantity: 2 },\n * { region: 'North', product: 'Mouse', amount: 50, quantity: 5 },\n * { region: 'South', product: 'Laptop', amount: 1200, quantity: 3 }\n * ]\n *\n * // Group by region and calculate totals\n * const regionTotals = calculateAggregations(\n * { $sum: ['amount', 'quantity'], $avg: ['amount'] },\n * ['region'],\n * sales\n * )\n * // Result: [\n * // { region: 'North', amount$sum: 1050, quantity$sum: 7, amount$avg: 525 },\n * // { region: 'South', amount$sum: 1200, quantity$sum: 3, amount$avg: 1200 }\n * // ]\n *\n * // Overall totals (no grouping)\n * const totals = calculateAggregations(\n * { $sum: ['amount'], $count: ['product'], $countUniq: ['region'] },\n * [],\n * sales,\n * false\n * )\n * // Result: { amount: 2250, product: 3, region: 2 }\n * ```\n */\nexport const calculateAggregations = (\n operations: IMathOp,\n pgroupBy: string[],\n inData: any[],\n appendOperationToField = true\n) => {\n let data: any = []\n if (pgroupBy?.length) {\n const groupedData = groupBy(inData, item =>\n pgroupBy.map(field => get(item, field)).join('$|marca|@')\n )\n data = map(groupedData, (items, groupKey) => {\n const obj: any = zipObject(pgroupBy, groupKey.split('$|marca|@'))\n for (const operation in operations) {\n const fields = operations[operation]\n fields.forEach(field => {\n const resultField = appendOperationToField ? field + operation : field\n switch (operation) {\n case '$count':\n obj[resultField] = items.length\n break\n case '$sum':\n obj[resultField] = sumBy(items, item => get(item, field))\n break\n case '$avg':\n obj[resultField] = round(\n meanBy(items, item => get(item, field)),\n 1\n )\n break\n case '$max': {\n const maxItem = maxBy(items, item => get(item, field))\n obj[resultField] = maxItem ? get(maxItem, field) : undefined\n break\n }\n case '$min': {\n const minItem = minBy(items, item => get(item, field))\n obj[resultField] = minItem ? get(minItem, field) : undefined\n break\n }\n case '$exist':\n obj[resultField] = some(items, item => get(item, field)) ? 1 : 0\n break\n case '$trend':\n obj[resultField] = calculateTrendSlope(\n items.map(item => get(item, field)),\n items.map((_item, index) => index + 1)\n )\n break\n case '$countUniq':\n obj[resultField] = uniq(items.map(item => get(item, field))).length\n break\n }\n })\n }\n return obj\n })\n } else {\n const results: { [key: string]: number } = {}\n for (const operation in operations) {\n const fields = operations[operation]\n fields.forEach(field => {\n const resultField = appendOperationToField ? field + operation : field\n switch (operation) {\n case '$count':\n results[resultField] = inData.length\n break\n case '$sum':\n results[resultField] = sumBy(inData, field)\n break\n case '$avg':\n results[resultField] = round(meanBy(inData, field), 1)\n break\n case '$max':\n if (Array.isArray(inData)) {\n const maxItem = maxBy(inData, field)\n results[resultField] = maxItem ? maxItem[field] : undefined\n }\n break\n case '$min':\n if (Array.isArray(inData)) {\n const minItem = minBy(inData, field)\n results[resultField] = minItem ? minItem[field] : undefined\n }\n break\n case '$exist':\n results[resultField] = some(inData, { [field]: true }) ? 1 : 0\n break\n case '$trend':\n results[resultField] = calculateTrendSlope(\n inData.map(item => get(item, field)),\n inData.map((_item, index) => index + 1)\n )\n break\n case '$countUniq':\n results[resultField] = uniq(inData.map(item => get(item, field))).length\n break\n }\n })\n }\n data = results\n }\n return data\n}\n\n/**\n * Calculates the slope of a linear trend line using least squares regression\n *\n * Computes the \"rise over run\" coefficient that best fits the data points.\n * Uses the least squares method to find the line y = mx + b, returning only m (slope).\n *\n * Slope interpretation:\n * - **Positive slope**: Y increases as X increases (upward trend)\n * - **Negative slope**: Y decreases as X increases (downward trend)\n * - **Zero slope**: No trend, flat line\n * - **Magnitude**: How steep the trend is (larger = steeper)\n *\n * Algorithm (Least Squares):\n * 1. Calculate Σx, Σy, Σx², Σxy\n * 2. Compute slope: m = (n·Σxy - Σx·Σy) / (n·Σx² - (Σx)²)\n * 3. Handle division by zero (constant x values)\n * 4. Round to 1 decimal place\n *\n * @param y - Dependent variable values (response variable)\n * @param x - Independent variable values (predictor variable)\n * @returns Slope value rounded to 1 decimal (0 if denominator is zero)\n *\n * @example\n * ```typescript\n * // Basic trend slope calculation\n * const sales = [100, 120, 140, 160, 180]\n * const months = [1, 2, 3, 4, 5]\n * calculateTrendSlope(sales, months) // 20.0 (sales increase 20 units/month)\n *\n * const declining = [100, 90, 80, 70, 60]\n * calculateTrendSlope(declining, months) // -10.0 (decreasing 10 units/month)\n *\n * const flat = [100, 100, 100, 100, 100]\n * calculateTrendSlope(flat, months) // 0.0 (no trend)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sales forecasting and trend analysis\n * interface MonthlySales {\n * month: number\n * revenue: number\n * }\n *\n * function analyzeSalesTrend(data: MonthlySales[]): void {\n * const months = data.map(d => d.month)\n * const revenue = data.map(d => d.revenue)\n * const slope = calculateTrendSlope(revenue, months)\n *\n * console.log(`📈 Sales Trend Analysis:`)\n * console.log(` Slope: ${slope} per month`)\n *\n * if (slope > 0) {\n * const annualGrowth = slope * 12\n * console.log(`✅ Growing trend: $${annualGrowth.toLocaleString()}/year projected`)\n * } else if (slope < 0) {\n * console.log(`⚠️ Declining trend: ${slope} per month`)\n * console.log(`Action: Investigate causes and intervene`)\n * } else {\n * console.log(`➡️ Flat trend: No significant growth or decline`)\n * }\n * }\n *\n * const salesData = [\n * { month: 1, revenue: 50000 },\n * { month: 2, revenue: 52000 },\n * { month: 3, revenue: 54000 },\n * { month: 4, revenue: 56000 }\n * ]\n * analyzeSalesTrend(salesData)\n * // Slope: 2000 per month\n * // ✅ Growing: $24,000/year projected\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: User engagement trending\n * function trackUserEngagement(dailyActiveUsers: number[]): string {\n * const days = Array.from({ length: dailyActiveUsers.length }, (_, i) => i + 1)\n * const slope = calculateTrendSlope(dailyActiveUsers, days)\n *\n * const avgUsers = dailyActiveUsers.reduce((a, b) => a + b) / dailyActiveUsers.length\n * const changePercent = ((slope * 30) / avgUsers) * 100\n *\n * if (changePercent > 5) {\n * return `🚀 Strong growth: ${changePercent.toFixed(1)}% monthly increase`\n * } else if (changePercent < -5) {\n * return `📉 Declining: ${changePercent.toFixed(1)}% monthly decrease (ALERT!)`\n * } else {\n * return `➡️ Stable: ${changePercent.toFixed(1)}% monthly change`\n * }\n * }\n *\n * const dau = [1000, 1020, 1050, 1080, 1100, 1120, 1150]\n * trackUserEngagement(dau)\n * // \"🚀 Strong growth: 12.8% monthly increase\"\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Server response time degradation detection\n * function monitorPerformanceDegradation(\n * responseTimes: number[],\n * timestamps: number[]\n * ): void {\n * const slope = calculateTrendSlope(responseTimes, timestamps)\n *\n * console.log(`⏱️ Performance Trend: ${slope}ms per time unit`)\n *\n * if (slope > 5) {\n * console.log('🚨 ALERT: Response times degrading')\n * console.log(`Degradation rate: ${slope}ms per unit`)\n * console.log('Action: Investigate server load, memory leaks, database queries')\n * } else if (slope < -5) {\n * console.log('✅ Performance improving')\n * } else {\n * console.log('➡️ Performance stable')\n * }\n * }\n *\n * const times = [120, 125, 135, 150, 170, 200]\n * const hours = [1, 2, 3, 4, 5, 6]\n * monitorPerformanceDegradation(times, hours)\n * // 🚨 ALERT: Response times degrading (16ms/hour)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Stock price momentum indicator\n * function calculatePriceMomentum(prices: number[], days: number[]): string {\n * const slope = calculateTrendSlope(prices, days)\n * const avgPrice = prices.reduce((a, b) => a + b) / prices.length\n * const momentum = (slope / avgPrice) * 100\n *\n * if (momentum > 1) {\n * return `🟢 BULLISH (${momentum.toFixed(2)}% daily momentum)`\n * } else if (momentum < -1) {\n * return `🔴 BEARISH (${momentum.toFixed(2)}% daily momentum)`\n * } else {\n * return `🟡 NEUTRAL (${momentum.toFixed(2)}% daily momentum)`\n * }\n * }\n *\n * const stockPrices = [100, 102, 105, 108, 112, 115]\n * const tradingDays = [1, 2, 3, 4, 5, 6]\n * calculatePriceMomentum(stockPrices, tradingDays)\n * // \"🟢 BULLISH (2.86% daily momentum)\"\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * calculateTrendSlope([1, 2, 3], [1, 2, 3]) // 1.0 (perfect positive correlation)\n * calculateTrendSlope([3, 2, 1], [1, 2, 3]) // -1.0 (perfect negative)\n * calculateTrendSlope([5, 5, 5], [1, 2, 3]) // 0.0 (flat line)\n * calculateTrendSlope([1, 2, 3], [1, 1, 1]) // 0.0 (constant X, div by zero)\n * calculateTrendSlope([10, 20], [1, 2]) // 10.0 (two points)\n * ```\n *\n * @see {@link calculateCorrelation} for correlation strength (not just slope)\n * @see {@link calculateAverage} for mean calculation\n */\nexport function calculateTrendSlope(y: number[], x: number[]) {\n const n = size(y)\n const sum_x = sum(x)\n const sum_y = sum(y)\n const sum_x2 = sum(map(x, val => val * val))\n const sum_xy = sum(map(x, (val, i) => val * y[i]))\n\n const denominator = n * sum_x2 - sum_x * sum_x\n if (denominator === 0) {\n return 0\n }\n\n const slope = (n * sum_xy - sum_x * sum_y) / denominator\n return roundToDecimals(slope, 1)\n}\n\n// =============================================================================\n// ADVANCED STATISTICAL FUNCTIONS\n// =============================================================================\n\n/**\n * Calculates the median of an array of numbers\n *\n * The median is the middle value in a sorted dataset. More robust than mean for\n * skewed distributions or datasets with outliers. For even-length arrays, returns\n * the average of the two middle values.\n *\n * Algorithm:\n * 1. Sort array in ascending order\n * 2. If odd length: return middle value\n * 3. If even length: return average of two middle values\n * 4. Empty array returns 0\n *\n * Use cases: Income analysis, response times, test scores, real estate prices\n *\n * @param values - Array of numbers to calculate median from (empty array returns 0)\n * @returns Median value, or 0 if array is empty\n *\n * @example\n * ```typescript\n * // Odd number of values\n * calculateMedian([1, 2, 3, 4, 5]) // 3 (middle value)\n * calculateMedian([10, 5, 15]) // 10 (after sorting: [5, 10, 15])\n *\n * // Even number of values\n * calculateMedian([1, 2, 3, 4]) // 2.5 (average of 2 and 3)\n * calculateMedian([10, 20, 30, 40]) // 25 (average of 20 and 30)\n *\n * // Edge cases\n * calculateMedian([]) // 0\n * calculateMedian([42]) // 42\n * calculateMedian([5, 5, 5]) // 5\n *\n * // Handles negative numbers\n * calculateMedian([-10, -5, 0, 5, 10]) // 0\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Analyze salary data (median better than mean for skewed data)\n * const salaries = [30000, 35000, 40000, 45000, 50000, 250000]\n *\n * const mean = salaries.reduce((a, b) => a + b) / salaries.length\n * const median = calculateMedian(salaries)\n *\n * console.log(`Mean: $${mean}`) // $75,000 (skewed by outlier)\n * console.log(`Median: $${median}`) // $42,500 (more representative)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Website response time analysis\n * const responseTimes = [120, 150, 180, 200, 220, 5000] // milliseconds\n *\n * const medianResponseTime = calculateMedian(responseTimes)\n * console.log(`Median response: ${medianResponseTime}ms`) // 190ms\n * // More useful than mean (946ms) which is skewed by one slow request\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Grade distribution analysis\n * const grades = [65, 70, 75, 80, 85, 90, 95]\n *\n * const median = calculateMedian(grades)\n * const Q1 = calculatePercentile(grades, 25)\n * const Q3 = calculatePercentile(grades, 75)\n *\n * console.log(`Median grade: ${median}`) // 80\n * console.log(`25th percentile: ${Q1}`) // 70\n * console.log(`75th percentile: ${Q3}`) // 90\n * ```\n *\n * @see {@link calculateAverage} for arithmetic mean calculation\n * @see {@link calculatePercentile} for other percentiles (median is 50th percentile)\n * @see {@link calculateQuartiles} for Q1, Q2 (median), Q3\n * @see {@link calculateMode} for most frequent value\n */\nexport const calculateMedian = (values: number[]): number => {\n if (!values.length) return 0\n\n const sorted = [...values].sort((a, b) => a - b)\n const middle = Math.floor(sorted.length / 2)\n\n if (sorted.length % 2 === 0) {\n return (sorted[middle - 1] + sorted[middle]) / 2\n }\n\n return sorted[middle]\n}\n\n/**\n * Calculates the mode (most frequent value) in an array of numbers\n *\n * The mode is the value that appears most frequently in a dataset. Returns null\n * if the array is empty or if there are multiple modes (multimodal distribution).\n *\n * Algorithm:\n * 1. Count frequency of each value using hash map\n * 2. Track maximum frequency and corresponding value\n * 3. Detect multimodal distributions (multiple values with same max frequency)\n * 4. Return single mode or null if multimodal/empty\n *\n * Behavior:\n * - Empty array → null\n * - Single mode → returns that value\n * - Multiple modes (tie) → null\n * - All unique values → null (no mode)\n *\n * @param values - Array of numbers to analyze\n * @returns The mode (most frequent value) or null if multimodal/empty\n *\n * @example\n * ```typescript\n * // Basic mode calculation\n * calculateMode([1, 2, 2, 3, 3, 3, 4]) // 3 (appears 3 times)\n * calculateMode([5, 5, 5, 1, 2, 3]) // 5 (most frequent)\n * calculateMode([10, 20, 30]) // null (all unique, no mode)\n * calculateMode([1, 1, 2, 2, 3]) // null (multimodal: 1 and 2 tie)\n * calculateMode([]) // null (empty array)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Find most common response time in API logs\n * const responseTimes = [\n * 150, 200, 150, 300, 150, // 150ms appears most\n * 200, 400, 150, 200, 150\n * ]\n * const commonResponseTime = calculateMode(responseTimes)\n * // 150 (appears 5 times)\n *\n * if (commonResponseTime !== null) {\n * console.log(`Most common response time: ${commonResponseTime}ms`)\n * console.log('💡 Optimize for this latency profile')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect most frequent error code in logs\n * function analyzeErrorCodes(errorLogs: { code: number }[]): void {\n * const codes = errorLogs.map(log => log.code)\n * const mostFrequentCode = calculateMode(codes)\n *\n * if (mostFrequentCode !== null) {\n * console.log(`🚨 Most frequent error: ${mostFrequentCode}`)\n * console.log('Priority fix needed for this error type')\n * } else {\n * console.log('✅ No dominant error pattern (good distribution)')\n * }\n * }\n *\n * // Example usage\n * const errors = [\n * { code: 404 }, { code: 500 }, { code: 404 },\n * { code: 404 }, { code: 503 }, { code: 404 }\n * ]\n * analyzeErrorCodes(errors)\n * // 🚨 Most frequent error: 404\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Find most popular product rating\n * interface ProductReview {\n * productId: string\n * rating: number // 1-5 stars\n * userId: string\n * }\n *\n * function getMostCommonRating(reviews: ProductReview[]): string {\n * const ratings = reviews.map(r => r.rating)\n * const mode = calculateMode(ratings)\n *\n * if (mode === null) {\n * return 'Ratings are evenly distributed'\n * }\n *\n * const sentiment = mode >= 4 ? '😊 Positive' : mode <= 2 ? '😞 Negative' : '😐 Neutral'\n * return `Most common rating: ${mode}⭐ (${sentiment})`\n * }\n *\n * const reviews = [\n * { productId: 'A1', rating: 5, userId: 'U1' },\n * { productId: 'A1', rating: 5, userId: 'U2' },\n * { productId: 'A1', rating: 4, userId: 'U3' },\n * { productId: 'A1', rating: 5, userId: 'U4' }\n * ]\n *\n * getMostCommonRating(reviews)\n * // \"Most common rating: 5⭐ (😊 Positive)\"\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect most frequent user action in analytics\n * const userActions = [\n * 'click', 'scroll', 'click', 'click',\n * 'scroll', 'click', 'submit', 'click'\n * ].map(action => {\n * const actionMap = { click: 1, scroll: 2, submit: 3 }\n * return actionMap[action as keyof typeof actionMap]\n * })\n *\n * const dominantAction = calculateMode(userActions)\n * const actionNames = { 1: 'click', 2: 'scroll', 3: 'submit' }\n *\n * if (dominantAction !== null) {\n * console.log(`Most frequent action: ${actionNames[dominantAction as keyof typeof actionNames]}`)\n * // \"Most frequent action: click\"\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * calculateMode([42]) // 42 (single value)\n * calculateMode([1, 1]) // 1 (all same)\n * calculateMode([1, 2, 3, 4, 5]) // null (all unique)\n * calculateMode([1, 1, 2, 2]) // null (bimodal)\n * calculateMode([1, 1, 1, 2, 2, 2]) // null (bimodal tie)\n * calculateMode([NaN, NaN, 1]) // NaN (NaN counted as value)\n * calculateMode([Infinity, Infinity]) // Infinity\n * ```\n *\n * @see {@link calculateMedian} for middle value (resistant to outliers)\n * @see {@link calculateAverage} for mean value\n * @see {@link calculateStandardDeviation} for data spread measurement\n */\nexport const calculateMode = (values: number[]): number | null => {\n if (!values.length) return null\n\n const frequency: { [key: number]: number } = {}\n let maxFreq = 0\n let mode: number | null = null\n let hasMultipleModes = false\n\n for (const value of values) {\n frequency[value] = (frequency[value] || 0) + 1\n\n if (frequency[value] > maxFreq) {\n maxFreq = frequency[value]\n mode = value\n hasMultipleModes = false\n } else if (frequency[value] === maxFreq && value !== mode) {\n hasMultipleModes = true\n }\n }\n\n return hasMultipleModes ? null : mode\n}\n\n/**\n * Calculates the standard deviation of an array of numbers\n *\n * Measures the amount of variation or dispersion in a dataset. Low standard deviation\n * means values are close to the mean; high standard deviation means values are spread out.\n *\n * Algorithm:\n * 1. Calculate mean (average)\n * 2. Calculate squared differences from mean\n * 3. Calculate variance (average of squared differences)\n * 4. Return square root of variance\n *\n * Formula:\n * - Population: σ = √(Σ(x - μ)² / N)\n * - Sample: s = √(Σ(x - x̄)² / (N - 1))\n *\n * @param values - Array of numbers (empty array returns 0)\n * @param sample - If true, uses sample standard deviation (N-1). If false, uses population (N). Default: false\n * @returns Standard deviation, or 0 if array is empty\n *\n * @example\n * ```typescript\n * // Low standard deviation (values close together)\n * calculateStandardDeviation([10, 11, 12, 13, 14])\n * // ~1.41 (values tightly clustered)\n *\n * // High standard deviation (values spread out)\n * calculateStandardDeviation([1, 5, 20, 50, 100])\n * // ~35.96 (values widely dispersed)\n *\n * // Population vs Sample\n * const data = [2, 4, 6, 8, 10]\n * calculateStandardDeviation(data, false) // 2.83 (population)\n * calculateStandardDeviation(data, true) // 3.16 (sample, Bessel's correction)\n *\n * // Edge cases\n * calculateStandardDeviation([]) // 0\n * calculateStandardDeviation([5]) // 0\n * calculateStandardDeviation([5, 5, 5]) // 0 (no variation)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Quality control - manufacturing consistency\n * const widgetWeights = [98.5, 99.2, 100.1, 99.8, 100.3, 98.9]\n * const targetWeight = 100\n *\n * const mean = widgetWeights.reduce((a, b) => a + b) / widgetWeights.length\n * const stdDev = calculateStandardDeviation(widgetWeights, true)\n *\n * console.log(`Mean weight: ${mean.toFixed(2)}g`)\n * console.log(`Std deviation: ${stdDev.toFixed(2)}g`)\n * // Low std dev = consistent manufacturing\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Investment volatility analysis\n * const monthlyReturns = [2.3, -1.5, 4.2, 0.8, -2.1, 3.5, 1.2] // %\n *\n * const avgReturn = monthlyReturns.reduce((a, b) => a + b) / monthlyReturns.length\n * const volatility = calculateStandardDeviation(monthlyReturns, true)\n *\n * console.log(`Average return: ${avgReturn.toFixed(2)}%`)\n * console.log(`Volatility (std dev): ${volatility.toFixed(2)}%`)\n * // High volatility = riskier investment\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Student performance analysis\n * const testScores = [75, 82, 68, 90, 78, 85, 72, 88, 80, 77]\n *\n * const mean = testScores.reduce((a, b) => a + b) / testScores.length\n * const stdDev = calculateStandardDeviation(testScores, true)\n *\n * // Identify outliers (beyond 2 standard deviations)\n * const outliers = testScores.filter(score =>\n * Math.abs(score - mean) > 2 * stdDev\n * )\n *\n * console.log(`Mean: ${mean.toFixed(1)}`)\n * console.log(`Std Dev: ${stdDev.toFixed(1)}`)\n * console.log(`Outliers:`, outliers)\n * ```\n *\n * @see {@link calculateVariance} for variance (σ²)\n * @see {@link detectOutliers} for IQR-based outlier detection\n * @see {@link calculateMedian} for central tendency (robust to outliers)\n */\nexport const calculateStandardDeviation = (values: number[], sample = false): number => {\n if (!values.length) return 0\n\n const mean = values.reduce((sum, val) => sum + val, 0) / values.length\n const squaredDiffs = values.map(val => Math.pow(val - mean, 2))\n const variance =\n squaredDiffs.reduce((sum, val) => sum + val, 0) / (sample ? values.length - 1 : values.length)\n\n return Math.sqrt(variance)\n}\n\n/**\n * Calculates the variance of an array of numbers\n *\n * Variance measures how spread out numbers are from their mean (average).\n * It's the average of squared differences from the mean. Higher variance = more spread.\n *\n * Algorithm:\n * 1. Calculate mean (average) of all values\n * 2. Compute squared difference from mean for each value: (value - mean)²\n * 3. Sum all squared differences\n * 4. Divide by N (population) or N-1 (sample) depending on `sample` flag\n *\n * Population vs Sample variance:\n * - **Population (sample=false)**: Use when you have ALL data (divide by N)\n * - **Sample (sample=true)**: Use when you have a subset (divide by N-1, Bessel's correction)\n *\n * @param values - Array of numbers to analyze\n * @param sample - If true, uses sample variance (N-1). If false, uses population variance (N). Default: false\n * @returns Variance value (0 if empty array)\n *\n * @example\n * ```typescript\n * // Basic variance calculation\n * calculateVariance([1, 2, 3, 4, 5]) // 2 (population variance)\n * calculateVariance([1, 2, 3, 4, 5], true) // 2.5 (sample variance)\n * calculateVariance([10, 10, 10, 10]) // 0 (no variance, all same)\n * calculateVariance([1, 100]) // 2450.5 (high variance)\n * calculateVariance([]) // 0 (empty array)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Analyze server response time consistency\n * const responseTimes = [120, 150, 130, 145, 125, 140, 135] // milliseconds\n * const variance = calculateVariance(responseTimes)\n * const stdDev = Math.sqrt(variance)\n *\n * console.log(`Variance: ${variance.toFixed(2)}ms²`)\n * console.log(`Std Dev: ${stdDev.toFixed(2)}ms`)\n *\n * if (stdDev < 20) {\n * console.log('✅ Consistent performance')\n * } else {\n * console.log('⚠️ High variability - investigate outliers')\n * }\n * // Variance: 110.20ms²\n * // Std Dev: 10.50ms\n * // ✅ Consistent performance\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Quality control in manufacturing\n * interface Measurement {\n * batchId: string\n * weight: number // grams\n * }\n *\n * function checkBatchQuality(measurements: Measurement[]): boolean {\n * const weights = measurements.map(m => m.weight)\n * const variance = calculateVariance(weights)\n * const maxAcceptableVariance = 5 // Quality threshold\n *\n * if (variance <= maxAcceptableVariance) {\n * console.log('✅ Batch passes quality control')\n * console.log(`Variance: ${variance.toFixed(2)}g² (within tolerance)`)\n * return true\n * } else {\n * console.log('❌ Batch REJECTED - excessive variance')\n * console.log(`Variance: ${variance.toFixed(2)}g² (exceeds ${maxAcceptableVariance}g²)`)\n * return false\n * }\n * }\n *\n * const batch = [\n * { batchId: 'B001', weight: 100.2 },\n * { batchId: 'B001', weight: 100.5 },\n * { batchId: 'B001', weight: 99.8 },\n * { batchId: 'B001', weight: 100.1 }\n * ]\n *\n * checkBatchQuality(batch)\n * // ✅ Batch passes quality control\n * // Variance: 0.09g² (within tolerance)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Stock price volatility analysis\n * function analyzeStockVolatility(prices: number[]): string {\n * const variance = calculateVariance(prices, true) // Sample variance\n * const stdDev = Math.sqrt(variance)\n * const mean = prices.reduce((sum, p) => sum + p, 0) / prices.length\n * const coefficientOfVariation = (stdDev / mean) * 100\n *\n * if (coefficientOfVariation < 5) {\n * return `Low volatility (${coefficientOfVariation.toFixed(1)}% CV) - Stable stock`\n * } else if (coefficientOfVariation < 15) {\n * return `Moderate volatility (${coefficientOfVariation.toFixed(1)}% CV) - Normal fluctuation`\n * } else {\n * return `High volatility (${coefficientOfVariation.toFixed(1)}% CV) - Risky investment`\n * }\n * }\n *\n * const stockPrices = [100, 102, 98, 101, 99, 103, 97] // Daily closing prices\n * analyzeStockVolatility(stockPrices)\n * // \"Moderate volatility (2.1% CV) - Normal fluctuation\"\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: A/B test result significance\n * function compareVariability(groupA: number[], groupB: number[]): void {\n * const varA = calculateVariance(groupA, true)\n * const varB = calculateVariance(groupB, true)\n * const ratio = varA / varB\n *\n * console.log(`Group A variance: ${varA.toFixed(2)}`)\n * console.log(`Group B variance: ${varB.toFixed(2)}`)\n * console.log(`Variance ratio: ${ratio.toFixed(2)}`)\n *\n * if (ratio > 2 || ratio < 0.5) {\n * console.log('⚠️ Groups have significantly different variability')\n * console.log('Consider using Welch\\'s t-test instead of Student\\'s t-test')\n * } else {\n * console.log('✅ Groups have similar variability')\n * }\n * }\n *\n * const conversionRatesA = [0.12, 0.15, 0.13, 0.14, 0.12]\n * const conversionRatesB = [0.18, 0.22, 0.19, 0.21, 0.20]\n *\n * compareVariability(conversionRatesA, conversionRatesB)\n * // Group A variance: 0.00013\n * // Group B variance: 0.00025\n * // Variance ratio: 0.52\n * // ✅ Groups have similar variability\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * calculateVariance([5]) // 0 (single value)\n * calculateVariance([5], true) // NaN (sample size 1, division by 0)\n * calculateVariance([1, 1, 1]) // 0 (no variation)\n * calculateVariance([0, 0, 0]) // 0 (all zeros)\n * calculateVariance([-5, 0, 5]) // 16.67 (symmetric around 0)\n * calculateVariance([1e10, 1e10 + 1]) // 0.25 (large numbers)\n * ```\n *\n * @see {@link calculateStandardDeviation} for square root of variance (same units as data)\n * @see {@link calculateIQR} for robust spread measure (resistant to outliers)\n * @see {@link detectOutliers} for finding extreme values\n */\nexport const calculateVariance = (values: number[], sample = false): number => {\n if (!values.length) return 0\n\n const mean = values.reduce((sum, val) => sum + val, 0) / values.length\n const squaredDiffs = values.map(val => Math.pow(val - mean, 2))\n\n return (\n squaredDiffs.reduce((sum, val) => sum + val, 0) / (sample ? values.length - 1 : values.length)\n )\n}\n\n/**\n * Calculates a specific percentile from an array of numbers\n *\n * Percentiles indicate the value below which a given percentage of observations fall.\n * For example, the 75th percentile is the value below which 75% of the data lies.\n *\n * Algorithm:\n * 1. Sort values in ascending order\n * 2. Calculate position: (percentile / 100) × (n - 1)\n * 3. If position is integer, return value at that index\n * 4. Otherwise, interpolate between lower and upper values using linear interpolation\n *\n * Common percentiles:\n * - 25th (Q1): First quartile\n * - 50th (Q2): Median\n * - 75th (Q3): Third quartile\n * - 90th: Top 10% threshold\n * - 95th: Top 5% threshold\n * - 99th: Top 1% threshold\n *\n * @param values - Array of numbers to analyze\n * @param percentile - Percentile to calculate (0-100)\n * @returns Value at the specified percentile (0 if empty array)\n * @throws {Error} If percentile is not between 0 and 100\n *\n * @example\n * ```typescript\n * // Basic percentile calculation\n * const scores = [55, 60, 65, 70, 75, 80, 85, 90, 95, 100]\n *\n * calculatePercentile(scores, 25) // 66.25 (Q1 - 25% below this)\n * calculatePercentile(scores, 50) // 77.5 (Median - 50% below this)\n * calculatePercentile(scores, 75) // 88.75 (Q3 - 75% below this)\n * calculatePercentile(scores, 90) // 95.5 (90% below this)\n * calculatePercentile(scores, 100) // 100 (Maximum)\n * calculatePercentile(scores, 0) // 55 (Minimum)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: API response time SLA monitoring\n * const responseTimes = [\n * 120, 150, 180, 200, 250, 300, 350, 400, 450, 500,\n * 600, 700, 800, 1000, 1200\n * ]\n *\n * const p50 = calculatePercentile(responseTimes, 50) // Median\n * const p95 = calculatePercentile(responseTimes, 95) // 95th percentile\n * const p99 = calculatePercentile(responseTimes, 99) // 99th percentile\n *\n * console.log(`📊 Response Time SLA:`)\n * console.log(` 50th (median): ${p50}ms`)\n * console.log(` 95th: ${p95}ms`)\n * console.log(` 99th: ${p99}ms`)\n *\n * if (p95 < 500) {\n * console.log('✅ SLA met: 95% of requests under 500ms')\n * } else {\n * console.log(`⚠️ SLA breach: p95=${p95}ms exceeds 500ms target`)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Grade distribution analysis\n * function analyzeExamResults(scores: number[]): void {\n * const p10 = calculatePercentile(scores, 10)\n * const p25 = calculatePercentile(scores, 25)\n * const p50 = calculatePercentile(scores, 50)\n * const p75 = calculatePercentile(scores, 75)\n * const p90 = calculatePercentile(scores, 90)\n *\n * console.log('📈 Exam Score Distribution:')\n * console.log(` Bottom 10%: ≤ ${p10.toFixed(1)}`)\n * console.log(` Q1 (25th): ${p25.toFixed(1)}`)\n * console.log(` Median (50th): ${p50.toFixed(1)}`)\n * console.log(` Q3 (75th): ${p75.toFixed(1)}`)\n * console.log(` Top 10%: ≥ ${p90.toFixed(1)}`)\n *\n * // Identify struggling students\n * if (p25 < 60) {\n * console.log('⚠️ Warning: 25% of students scored below 60')\n * console.log('Recommendation: Provide additional support')\n * }\n * }\n *\n * const examScores = [45, 52, 58, 63, 67, 72, 75, 78, 82, 85, 88, 92, 95]\n * analyzeExamResults(examScores)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Server load capacity planning\n * interface ServerMetrics {\n * timestamp: Date\n * cpuUsage: number // percentage\n * }\n *\n * function determineCapacityThreshold(metrics: ServerMetrics[]): number {\n * const cpuUsages = metrics.map(m => m.cpuUsage)\n * const p95 = calculatePercentile(cpuUsages, 95)\n *\n * console.log(`Current p95 CPU usage: ${p95.toFixed(1)}%`)\n *\n * if (p95 > 80) {\n * console.log('🚨 CRITICAL: Scale up immediately')\n * return 100 // Emergency threshold\n * } else if (p95 > 60) {\n * console.log('⚠️ WARNING: Plan scaling in next 24h')\n * return 80\n * } else {\n * console.log('✅ Healthy capacity')\n * return 70\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Income inequality analysis (Gini coefficient context)\n * const householdIncomes = [\n * 25000, 30000, 35000, 40000, 45000, 50000, 55000,\n * 60000, 70000, 80000, 90000, 120000, 150000, 200000\n * ]\n *\n * const p10 = calculatePercentile(householdIncomes, 10)\n * const p50 = calculatePercentile(householdIncomes, 50)\n * const p90 = calculatePercentile(householdIncomes, 90)\n *\n * const p90p10Ratio = p90 / p10\n *\n * console.log(`Income distribution:`)\n * console.log(` Bottom 10%: ≤$${p10.toLocaleString()}`)\n * console.log(` Median: $${p50.toLocaleString()}`)\n * console.log(` Top 10%: ≥$${p90.toLocaleString()}`)\n * console.log(` P90/P10 ratio: ${p90p10Ratio.toFixed(2)}x`)\n *\n * if (p90p10Ratio > 5) {\n * console.log('⚠️ High income inequality detected')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * calculatePercentile([10], 50) // 10 (single value)\n * calculatePercentile([1, 2, 3, 4], 0) // 1 (minimum)\n * calculatePercentile([1, 2, 3, 4], 100) // 4 (maximum)\n * calculatePercentile([], 50) // 0 (empty array)\n * calculatePercentile([5, 5, 5], 75) // 5 (all same values)\n *\n * // Error cases\n * calculatePercentile([1, 2, 3], -1) // throws Error\n * calculatePercentile([1, 2, 3], 101) // throws Error\n * ```\n *\n * @see {@link calculateQuartiles} for Q1, Q2, Q3 in one call\n * @see {@link calculateIQR} for interquartile range (Q3 - Q1)\n * @see {@link calculateMedian} for 50th percentile specifically\n * @see {@link detectOutliers} for finding extreme values using IQR method\n */\nexport const calculatePercentile = (values: number[], percentile: number): number => {\n if (!values.length) return 0\n if (percentile < 0 || percentile > 100) throw new Error('Percentile must be between 0 and 100')\n\n const sorted = [...values].sort((a, b) => a - b)\n const index = (percentile / 100) * (sorted.length - 1)\n\n if (Math.floor(index) === index) {\n return sorted[index]\n }\n\n const lower = sorted[Math.floor(index)]\n const upper = sorted[Math.ceil(index)]\n const weight = index - Math.floor(index)\n\n return lower * (1 - weight) + upper * weight\n}\n\n/**\n * Calculates quartiles (Q1, Q2, Q3) of an array of numbers\n *\n * Quartiles divide a sorted dataset into four equal parts. Returns the three cut points:\n * - **Q1 (25th percentile)**: 25% of data below, 75% above\n * - **Q2 (50th percentile)**: Median - 50% below, 50% above\n * - **Q3 (75th percentile)**: 75% below, 25% above\n *\n * Useful for:\n * - Box plot visualization\n * - Outlier detection (IQR method)\n * - Understanding data spread and skewness\n * - Five-number summary (min, Q1, Q2, Q3, max)\n *\n * @param values - Array of numbers to analyze\n * @returns Object with Q1, Q2 (median), Q3 values\n *\n * @example\n * ```typescript\n * // Basic quartiles\n * const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n * calculateQuartiles(data)\n * // { Q1: 3.25, Q2: 5.5, Q3: 7.75 }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Salary distribution analysis\n * const salaries = [\n * 30000, 35000, 40000, 45000, 50000, 55000, 60000,\n * 65000, 70000, 80000, 90000, 120000\n * ]\n *\n * const { Q1, Q2, Q3 } = calculateQuartiles(salaries)\n *\n * console.log(`📊 Salary Distribution:`)\n * console.log(` Q1 (25th): $${Q1.toLocaleString()}`)\n * console.log(` Q2 (Median): $${Q2.toLocaleString()}`)\n * console.log(` Q3 (75th): $${Q3.toLocaleString()}`)\n * console.log(` IQR: $${(Q3 - Q1).toLocaleString()}`)\n * // Q1: $43,750, Q2: $57,500, Q3: $72,500, IQR: $28,750\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Performance monitoring box plot\n * function createBoxPlot(responseTimes: number[]): void {\n * const { Q1, Q2, Q3 } = calculateQuartiles(responseTimes)\n * const min = Math.min(...responseTimes)\n * const max = Math.max(...responseTimes)\n * const iqr = Q3 - Q1\n *\n * console.log('📦 Response Time Box Plot:')\n * console.log(` Min: ${min}ms`)\n * console.log(` Q1: ${Q1}ms ├───┐`)\n * console.log(` Q2: ${Q2}ms │ █ │ (median)`)\n * console.log(` Q3: ${Q3}ms └───┤`)\n * console.log(` Max: ${max}ms`)\n * console.log(` IQR: ${iqr}ms (middle 50%)`)\n * }\n *\n * const times = [120, 150, 180, 200, 220, 250, 300, 350, 400]\n * createBoxPlot(times)\n * ```\n *\n * @see {@link calculatePercentile} for calculating any percentile\n * @see {@link calculateIQR} for interquartile range (Q3 - Q1)\n * @see {@link detectOutliers} for outlier detection using quartiles\n * @see {@link calculateMedian} for Q2 specifically\n */\nexport const calculateQuartiles = (values: number[]): { Q1: number; Q2: number; Q3: number } => {\n return {\n Q1: calculatePercentile(values, 25),\n Q2: calculatePercentile(values, 50), // median\n Q3: calculatePercentile(values, 75),\n }\n}\n\n/**\n * Calculates the interquartile range (IQR) of an array of numbers\n *\n * IQR is the range of the middle 50% of data, calculated as Q3 - Q1.\n * It's a robust measure of statistical dispersion, resistant to outliers.\n *\n * IQR interpretation:\n * - **Small IQR**: Data tightly clustered around median (low variability)\n * - **Large IQR**: Data widely spread (high variability)\n * - **IQR = 0**: All middle 50% values identical\n *\n * Key uses:\n * - Outlier detection (values outside Q1 - 1.5×IQR to Q3 + 1.5×IQR)\n * - Box plot whiskers calculation\n * - Robust alternative to standard deviation (less affected by extremes)\n *\n * @param values - Array of numbers to analyze\n * @returns Interquartile range (Q3 - Q1)\n *\n * @example\n * ```typescript\n * // Basic IQR calculation\n * const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n * calculateIQR(data) // 4.5 (middle 50% spans 4.5 units)\n *\n * const tightData = [10, 10.5, 11, 11.5, 12]\n * calculateIQR(tightData) // 1 (low variability)\n *\n * const spreadData = [10, 20, 30, 40, 50, 60, 70, 80, 90]\n * calculateIQR(spreadData) // 40 (high variability)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Compare consistency between two groups\n * const teamA_responseTimes = [100, 110, 120, 130, 140, 150]\n * const teamB_responseTimes = [80, 120, 130, 140, 180, 250]\n *\n * const iqrA = calculateIQR(teamA_responseTimes) // 30ms\n * const iqrB = calculateIQR(teamB_responseTimes) // 60ms\n *\n * console.log(`Team A IQR: ${iqrA}ms (consistent)`)\n * console.log(`Team B IQR: ${iqrB}ms (inconsistent)`)\n *\n * if (iqrB > iqrA * 1.5) {\n * console.log('⚠️ Team B shows high variability - investigate')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Quality control tolerance check\n * function checkProductQuality(measurements: number[]): boolean {\n * const iqr = calculateIQR(measurements)\n * const maxAllowedIQR = 5 // mm tolerance\n *\n * console.log(`IQR: ${iqr.toFixed(2)}mm`)\n *\n * if (iqr <= maxAllowedIQR) {\n * console.log('✅ Manufacturing process within tolerance')\n * return true\n * } else {\n * console.log(`❌ IQR ${iqr}mm exceeds ${maxAllowedIQR}mm tolerance`)\n * console.log('Action: Recalibrate machinery')\n * return false\n * }\n * }\n *\n * const partLengths = [99.8, 100.0, 100.1, 100.2, 100.3]\n * checkProductQuality(partLengths)\n * ```\n *\n * @see {@link calculateQuartiles} for Q1, Q2, Q3 values\n * @see {@link detectOutliers} for IQR-based outlier detection\n * @see {@link calculateStandardDeviation} for parametric dispersion measure\n */\nexport const calculateIQR = (values: number[]): number => {\n const quartiles = calculateQuartiles(values)\n return quartiles.Q3 - quartiles.Q1\n}\n\n/**\n * Detects outliers using the IQR (Interquartile Range) method\n *\n * Identifies values that fall outside the \"normal\" range defined by quartiles.\n * Uses Tukey's fences method, commonly used in box plots.\n *\n * Algorithm:\n * 1. Calculate Q1, Q3, and IQR (Q3 - Q1)\n * 2. Compute lower fence: Q1 - (multiplier × IQR)\n * 3. Compute upper fence: Q3 + (multiplier × IQR)\n * 4. Values outside fences are outliers\n *\n * Common multipliers:\n * - **1.5** (default): Standard outliers (Tukey's rule)\n * - **3.0**: Extreme outliers only (more conservative)\n *\n * @param values - Array of numbers to analyze\n * @param multiplier - IQR multiplier for fence calculation (default: 1.5)\n * @returns Array of outlier values\n *\n * @example\n * ```typescript\n * // Basic outlier detection\n * const data = [10, 12, 14, 15, 16, 18, 20, 22, 100]\n * detectOutliers(data) // [100] (extreme high value)\n *\n * const normal = [10, 12, 14, 15, 16, 18, 20, 22, 24]\n * detectOutliers(normal) // [] (no outliers)\n *\n * const withExtremes = [1, 10, 12, 14, 15, 16, 18, 20, 100]\n * detectOutliers(withExtremes) // [1, 100] (both low and high outliers)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect anomalous response times\n * function analyzeResponseTimes(times: number[]): void {\n * const outliers = detectOutliers(times)\n *\n * if (outliers.length === 0) {\n * console.log('✅ No anomalous response times detected')\n * return\n * }\n *\n * const { Q1, Q3 } = calculateQuartiles(times)\n * const iqr = Q3 - Q1\n *\n * console.log(`⚠️ Found ${outliers.length} outliers:`)\n * outliers.forEach(outlier => {\n * const severity = outlier > Q3 + 3 * iqr ? 'EXTREME' : 'MODERATE'\n * console.log(` - ${outlier}ms (${severity})`)\n * })\n *\n * console.log('Recommendation: Investigate these requests')\n * }\n *\n * const apiTimes = [100, 120, 130, 140, 150, 160, 180, 200, 5000]\n * analyzeResponseTimes(apiTimes)\n * // ⚠️ Found 1 outliers:\n * // - 5000ms (EXTREME)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Fraud detection in transaction amounts\n * interface Transaction {\n * id: string\n * amount: number\n * userId: string\n * }\n *\n * function detectSuspiciousTransactions(\n * transactions: Transaction[]\n * ): Transaction[] {\n * const amounts = transactions.map(t => t.amount)\n * const outlierAmounts = detectOutliers(amounts, 3) // More conservative\n *\n * const suspicious = transactions.filter(t =>\n * outlierAmounts.includes(t.amount)\n * )\n *\n * if (suspicious.length > 0) {\n * console.log(`🚨 ${suspicious.length} suspicious transactions:`)\n * suspicious.forEach(t => {\n * console.log(` ID: ${t.id}, Amount: $${t.amount}, User: ${t.userId}`)\n * })\n * console.log('Action: Flag for manual review')\n * }\n *\n * return suspicious\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sensor data cleaning\n * function cleanSensorReadings(readings: number[]): number[] {\n * const outliers = detectOutliers(readings)\n * const cleaned = readings.filter(r => !outliers.includes(r))\n *\n * console.log(`Original readings: ${readings.length}`)\n * console.log(`Outliers removed: ${outliers.length}`)\n * console.log(`Cleaned readings: ${cleaned.length}`)\n *\n * if (outliers.length > readings.length * 0.1) {\n * console.log('⚠️ Warning: >10% outliers - sensor malfunction?')\n * }\n *\n * return cleaned\n * }\n *\n * const tempReadings = [20.1, 20.5, 20.8, 21.0, 85.0, 20.9, 21.2]\n * const clean = cleanSensorReadings(tempReadings)\n * // Original: 7, Outliers: 1 (85.0°C), Cleaned: 6\n * ```\n *\n * @example\n * ```typescript\n * // Comparing multipliers\n * const data = [1, 5, 10, 12, 14, 15, 16, 18, 20, 25, 100]\n *\n * detectOutliers(data, 1.5) // [1, 100] (standard)\n * detectOutliers(data, 3.0) // [100] (extreme only)\n * ```\n *\n * @see {@link calculateIQR} for IQR calculation\n * @see {@link calculateQuartiles} for quartile values\n * @see {@link calculateStandardDeviation} for parametric outlier detection (z-score method)\n */\nexport const detectOutliers = (values: number[], multiplier = 1.5): number[] => {\n const quartiles = calculateQuartiles(values)\n const iqr = quartiles.Q3 - quartiles.Q1\n const lowerBound = quartiles.Q1 - multiplier * iqr\n const upperBound = quartiles.Q3 + multiplier * iqr\n\n return values.filter(value => value < lowerBound || value > upperBound)\n}\n\n/**\n * Calculates Pearson correlation coefficient between two arrays of numbers\n *\n * Measures linear correlation between two variables. Returns value between -1 and +1:\n * - +1: Perfect positive correlation (as X increases, Y increases proportionally)\n * - 0: No linear correlation\n * - -1: Perfect negative correlation (as X increases, Y decreases proportionally)\n *\n * Formula (Pearson's r):\n * r = [n∑(xy) - ∑x∑y] / √{[n∑x² - (∑x)²][n∑y² - (∑y)²]}\n *\n * Use cases: A/B testing, feature selection, risk analysis, data validation\n *\n * ⚠️ NOTE: Measures LINEAR correlation only. May miss non-linear relationships.\n *\n * @param x - First array of numbers (must match length of y)\n * @param y - Second array of numbers (must match length of x)\n * @returns Correlation coefficient (-1 to +1), or 0 if arrays empty/mismatched/no variance\n *\n * @example\n * ```typescript\n * // Perfect positive correlation\n * calculateCorrelation([1, 2, 3, 4, 5], [2, 4, 6, 8, 10])\n * // 1.0 (perfect linear relationship: y = 2x)\n *\n * // Perfect negative correlation\n * calculateCorrelation([1, 2, 3, 4, 5], [10, 8, 6, 4, 2])\n * // -1.0 (perfect inverse relationship)\n *\n * // No correlation\n * calculateCorrelation([1, 2, 3, 4, 5], [5, 3, 5, 3, 5])\n * // ~0 (no linear relationship)\n *\n * // Moderate positive correlation\n * calculateCorrelation([1, 2, 3, 4, 5], [2, 3, 5, 7, 9])\n * // ~0.98 (strong positive correlation)\n *\n * // Edge cases\n * calculateCorrelation([], []) // 0\n * calculateCorrelation([1, 2], [1]) // 0 (length mismatch)\n * calculateCorrelation([5, 5, 5], [1, 2, 3]) // 0 (no variance in x)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Analyze relationship between ad spend and sales\n * const adSpend = [1000, 1500, 2000, 2500, 3000, 3500] // $ thousands\n * const sales = [20, 28, 35, 42, 48, 55] // $ thousands\n *\n * const correlation = calculateCorrelation(adSpend, sales)\n * console.log(`Correlation: ${correlation.toFixed(3)}`)\n * // 0.998 (strong positive correlation - more ad spend → more sales)\n *\n * if (correlation > 0.7) {\n * console.log('✅ Strong relationship: Ad spend drives sales')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Website traffic vs conversion rate analysis\n * const dailyVisitors = [1200, 1500, 1800, 2000, 2200, 2500]\n * const conversionRate = [3.2, 3.0, 2.9, 2.7, 2.6, 2.4]\n *\n * const correlation = calculateCorrelation(dailyVisitors, conversionRate)\n * console.log(`Correlation: ${correlation.toFixed(3)}`)\n * // -0.995 (strong negative correlation - more traffic → lower conversion %)\n * // Suggests traffic quality decreasing or server overload\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Feature selection for ML model\n * interface DataPoint {\n * temperature: number\n * humidity: number\n * windSpeed: number\n * rainfall: number\n * }\n *\n * const weatherData: DataPoint[] = [\n * { temperature: 25, humidity: 60, windSpeed: 10, rainfall: 0 },\n * { temperature: 30, humidity: 50, windSpeed: 15, rainfall: 2 },\n * { temperature: 20, humidity: 80, windSpeed: 5, rainfall: 10 },\n * // ... more data\n * ]\n *\n * // Find which features correlate with rainfall\n * const temp = weatherData.map(d => d.temperature)\n * const humidity = weatherData.map(d => d.humidity)\n * const wind = weatherData.map(d => d.windSpeed)\n * const rain = weatherData.map(d => d.rainfall)\n *\n * const correlations = {\n * temperature: calculateCorrelation(temp, rain),\n * humidity: calculateCorrelation(humidity, rain),\n * windSpeed: calculateCorrelation(wind, rain)\n * }\n *\n * console.log('Rainfall correlations:', correlations)\n * // { temperature: -0.45, humidity: 0.82, windSpeed: -0.23 }\n * // Humidity strongly predicts rainfall\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Portfolio diversification analysis\n * const stock1Returns = [2.3, -1.5, 4.2, 0.8, -2.1, 3.5]\n * const stock2Returns = [1.8, 2.1, -0.5, 1.2, 3.4, -1.8]\n *\n * const correlation = calculateCorrelation(stock1Returns, stock2Returns)\n * console.log(`Portfolio correlation: ${correlation.toFixed(3)}`)\n *\n * if (Math.abs(correlation) < 0.3) {\n * console.log('✅ Good diversification: Stocks move independently')\n * } else if (correlation > 0.7) {\n * console.log('⚠️ High correlation: Portfolio not diversified')\n * }\n * ```\n *\n * @see {@link calculateStandardDeviation} for measuring spread\n * @see {@link calculateTrendSlope} for linear regression slope\n * @see {@link https://en.wikipedia.org/wiki/Pearson_correlation_coefficient Pearson Correlation}\n */\nexport const calculateCorrelation = (x: number[], y: number[]): number => {\n if (x.length !== y.length || x.length === 0) return 0\n\n const n = x.length\n const sumX = sum(x)\n const sumY = sum(y)\n const sumXY = sum(map(x, (val, i) => val * y[i]))\n const sumX2 = sum(map(x, val => val * val))\n const sumY2 = sum(map(y, val => val * val))\n\n const numerator = n * sumXY - sumX * sumY\n const denominator = Math.sqrt((n * sumX2 - sumX * sumX) * (n * sumY2 - sumY * sumY))\n\n if (denominator === 0) return 0\n\n return numerator / denominator\n}\n\n// =============================================================================\n// FINANCIAL FUNCTIONS\n// =============================================================================\n\n/**\n * Calculates Net Present Value (NPV) of cash flows using discounted cash flow method\n *\n * Evaluates investment profitability by discounting future cash flows to present value.\n * Formula: NPV = CF₀ + CF₁/(1+r) + CF₂/(1+r)² + ... + CFₙ/(1+r)ⁿ\n *\n * Decision rules:\n * - NPV > 0: Investment profitable, accept project\n * - NPV = 0: Break-even, neutral decision\n * - NPV < 0: Investment unprofitable, reject project\n *\n * @param cashFlows - Array of cash flows [initial investment (negative), period 1, period 2, ...]\n * @param discountRate - Discount rate as decimal (e.g., 0.1 for 10% WACC/hurdle rate)\n * @returns Net Present Value in currency units\n *\n * @example\n * ```typescript\n * // Investment: -10000€ initial, then +3000€/year for 4 years\n * const npv = calculateNPV([-10000, 3000, 3000, 3000, 3000], 0.10)\n * console.log(npv) // 1509.67€ (profitable investment)\n *\n * // Real-world: Software project ROI analysis\n * const projectCashFlows = [\n * -50000, // Year 0: Development cost\n * 15000, // Year 1: Revenue\n * 20000, // Year 2: Revenue\n * 25000, // Year 3: Revenue\n * 30000 // Year 4: Revenue\n * ]\n * const wacc = 0.12 // 12% weighted average cost of capital\n * const projectNPV = calculateNPV(projectCashFlows, wacc)\n * if (projectNPV > 0) {\n * console.log(`✅ Project approved. NPV: ${projectNPV.toFixed(2)}€`)\n * }\n * ```\n *\n * @see {@link calculateIRR} for internal rate of return\n * @see {@link https://en.wikipedia.org/wiki/Net_present_value NPV Formula}\n */\nexport const calculateNPV = (cashFlows: number[], discountRate: number): number => {\n return cashFlows.reduce((npv, cashFlow, index) => {\n // Initial cash flow (usually investment) is not discounted\n // Subsequent cash flows are discounted by their period\n const discountFactor = index === 0 ? 1 : Math.pow(1 + discountRate, index)\n return npv + cashFlow / discountFactor\n }, 0)\n}\n\n/**\n * Calculates Internal Rate of Return (IRR) using Newton-Raphson iterative method\n *\n * Finds discount rate that makes NPV = 0. IRR represents the annualized effective return rate.\n * Uses Newton-Raphson numerical method with configurable tolerance and iterations.\n *\n * Decision rules:\n * - IRR > Required Rate: Accept project (returns exceed cost of capital)\n * - IRR < Required Rate: Reject project (insufficient returns)\n *\n * @param cashFlows - Array of cash flows [initial investment, period 1, period 2, ...]\n * @param initialGuess - Starting guess for IRR (default: 0.1 = 10%)\n * @param maxIterations - Maximum iterations for convergence (default: 100)\n * @param tolerance - Convergence tolerance (default: 1e-6)\n * @returns Internal Rate of Return as decimal (e.g., 0.15 = 15% annual return)\n *\n * @example\n * ```typescript\n * // Investment: -1000€, returns +400€, +500€, +300€\n * const irr = calculateIRR([-1000, 400, 500, 300])\n * console.log(`${(irr * 100).toFixed(2)}%`) // ~16.17% annual return\n *\n * // Real-world: Compare to required return rate\n * const cashFlows = [-50000, 15000, 20000, 25000, 30000]\n * const irr = calculateIRR(cashFlows)\n * const requiredRate = 0.12 // 12% hurdle rate\n *\n * if (irr > requiredRate) {\n * console.log(`✅ IRR ${(irr*100).toFixed(1)}% exceeds ${(requiredRate*100)}% requirement`)\n * } else {\n * console.log(`❌ IRR ${(irr*100).toFixed(1)}% below ${(requiredRate*100)}% requirement`)\n * }\n * ```\n *\n * @see {@link calculateNPV} for net present value calculation\n * @see {@link https://en.wikipedia.org/wiki/Internal_rate_of_return IRR Formula}\n */\nexport const calculateIRR = (\n cashFlows: number[],\n initialGuess = 0.1,\n maxIterations = 100,\n tolerance = 1e-6\n): number => {\n let rate = initialGuess\n\n for (let i = 0; i < maxIterations; i++) {\n const npv = calculateNPV(cashFlows, rate)\n const npvDerivative = cashFlows.reduce((sum, cashFlow, index) => {\n return sum - (index * cashFlow) / Math.pow(1 + rate, index + 1)\n }, 0)\n\n if (Math.abs(npv) < tolerance) return rate\n if (Math.abs(npvDerivative) < tolerance) break\n\n rate = rate - npv / npvDerivative\n }\n\n return rate\n}\n\n/**\n * Calculates future value (FV) with compound interest\n *\n * Formula: FV = PV × (1 + r)ⁿ\n *\n * @param presentValue - Initial investment amount\n * @param interestRate - Interest rate per period as decimal (e.g., 0.05 for 5%)\n * @param periods - Number of compounding periods\n * @returns Future value after n periods\n *\n * @example\n * ```typescript\n * // 1000€ at 5% annual interest for 10 years\n * const fv = calculateFutureValue(1000, 0.05, 10) // 1628.89€\n *\n * // Retirement planning: 10000€ invested for 30 years at 7%\n * const retirement = calculateFutureValue(10000, 0.07, 30) // 76,122.55€\n * ```\n *\n * @see {@link calculatePresentValue}\n */\nexport const calculateFutureValue = (\n presentValue: number,\n interestRate: number,\n periods: number\n): number => {\n return presentValue * Math.pow(1 + interestRate, periods)\n}\n\n/**\n * Calculates present value (PV) of future amount\n *\n * Formula: PV = FV / (1 + r)ⁿ\n *\n * @param futureValue - Future amount to discount\n * @param interestRate - Discount rate as decimal (e.g., 0.05 for 5%)\n * @param periods - Number of periods\n * @returns Present value today\n *\n * @example\n * ```typescript\n * // What's 10000€ in 5 years worth today at 6% discount?\n * const pv = calculatePresentValue(10000, 0.06, 5) // 7,472.58€\n * ```\n *\n * @see {@link calculateFutureValue}\n */\nexport const calculatePresentValue = (\n futureValue: number,\n interestRate: number,\n periods: number\n): number => {\n return futureValue / Math.pow(1 + interestRate, periods)\n}\n\n/**\n * Calculates periodic payment for annuity (loans, mortgages)\n *\n * Formula: PMT = PV × [r(1+r)ⁿ] / [(1+r)ⁿ - 1]\n *\n * @param presentValue - Loan/mortgage principal amount\n * @param interestRate - Interest rate per period as decimal\n * @param periods - Total number of payment periods\n * @returns Periodic payment amount\n *\n * @example\n * ```typescript\n * // 200000€ mortgage at 3% annual for 30 years (360 months)\n * const monthlyRate = 0.03 / 12 // 0.0025\n * const payment = calculateAnnuityPayment(200000, monthlyRate, 360) // 843.21€/month\n *\n * // Car loan: 25000€ at 5% for 5 years\n * const carPayment = calculateAnnuityPayment(25000, 0.05/12, 60) // 471.78€/month\n * ```\n */\nexport const calculateAnnuityPayment = (\n presentValue: number,\n interestRate: number,\n periods: number\n): number => {\n if (interestRate === 0) return presentValue / periods\n\n return (\n (presentValue * (interestRate * Math.pow(1 + interestRate, periods))) /\n (Math.pow(1 + interestRate, periods) - 1)\n )\n}\n\n// =============================================================================\n// DATA VISUALIZATION UTILITIES\n// =============================================================================\n\n/**\n * Normalizes an array of numbers to [0, 1] range using min-max normalization\n *\n * Transforms values to a common scale where:\n * - Minimum value → 0\n * - Maximum value → 1\n * - Other values → proportional between 0 and 1\n *\n * Formula: normalized = (value - min) / (max - min)\n *\n * Use cases:\n * - Machine learning feature scaling\n * - Comparing datasets with different scales\n * - Data visualization (heatmaps, gradients)\n * - Neural network input preprocessing\n *\n * @param values - Array of numbers to normalize\n * @returns Array normalized to [0, 1] range (empty array returns [], all equal returns all 0s)\n *\n * @example\n * ```typescript\n * // Basic normalization\n * normalizeToRange([10, 20, 30, 40, 50])\n * // [0, 0.25, 0.5, 0.75, 1]\n *\n * normalizeToRange([100, 200, 150])\n * // [0, 1, 0.5]\n *\n * normalizeToRange([5, 5, 5])\n * // [0, 0, 0] (all equal, no range)\n *\n * normalizeToRange([])\n * // [] (empty array)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Student grade normalization for comparison\n * interface StudentScore {\n * name: string\n * rawScore: number\n * }\n *\n * function normalizeScores(students: StudentScore[]): void {\n * const rawScores = students.map(s => s.rawScore)\n * const normalized = normalizeToRange(rawScores)\n *\n * students.forEach((student, i) => {\n * const normalizedScore = (normalized[i] * 100).toFixed(1)\n * console.log(`${student.name}: ${student.rawScore} → ${normalizedScore}%`)\n * })\n * }\n *\n * normalizeScores([\n * { name: 'Alice', rawScore: 85 },\n * { name: 'Bob', rawScore: 72 },\n * { name: 'Charlie', rawScore: 95 }\n * ])\n * // Alice: 85 → 56.5%\n * // Bob: 72 → 0.0%\n * // Charlie: 95 → 100.0%\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sensor data visualization (temperature heatmap)\n * function generateHeatmapColors(temperatures: number[]): string[] {\n * const normalized = normalizeToRange(temperatures)\n *\n * return normalized.map(value => {\n * const intensity = Math.round(value * 255)\n * return `rgb(${intensity}, 0, ${255 - intensity})`\n * })\n * }\n *\n * const temps = [18, 22, 25, 30, 35]\n * generateHeatmapColors(temps)\n * // ['rgb(0, 0, 255)', 'rgb(60, 0, 195)', ...]\n * // Blue (cold) → Red (hot)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: ML feature scaling for neural network\n * interface HouseData {\n * sqft: number // 500-5000\n * price: number // 100000-1000000\n * bedrooms: number // 1-6\n * }\n *\n * function prepareMLFeatures(houses: HouseData[]): number[][] {\n * const sqfts = normalizeToRange(houses.map(h => h.sqft))\n * const prices = normalizeToRange(houses.map(h => h.price))\n * const bedrooms = normalizeToRange(houses.map(h => h.bedrooms))\n *\n * return sqfts.map((_, i) => [sqfts[i], prices[i], bedrooms[i]])\n * }\n *\n * // All features now in [0, 1] range for training\n * ```\n *\n * @see {@link scaleToRange} for normalizing to custom [min, max] range\n * @see {@link calculateStandardDeviation} for z-score normalization alternative\n */\nexport const normalizeToRange = (values: number[]): number[] => {\n if (!values.length) return []\n\n const min = Math.min(...values)\n const max = Math.max(...values)\n const range = max - min\n\n if (range === 0) return values.map(() => 0)\n\n return values.map(value => (value - min) / range)\n}\n\n/**\n * Scales an array of numbers to a custom [min, max] range\n *\n * Transforms values to specified range while preserving proportions.\n * Uses min-max normalization internally, then scales to target range.\n *\n * Formula:\n * 1. Normalize to [0, 1]: norm = (value - min) / (max - min)\n * 2. Scale to [minRange, maxRange]: scaled = minRange + norm × (maxRange - minRange)\n *\n * Use cases:\n * - Image pixel values (0-255)\n * - Audio amplitude (-1 to 1)\n * - Progress bars (0-100%)\n * - Rating systems (1-5 stars)\n *\n * @param values - Array of numbers to scale\n * @param minRange - Target minimum value\n * @param maxRange - Target maximum value\n * @returns Array scaled to [minRange, maxRange]\n *\n * @example\n * ```typescript\n * // Basic scaling\n * scaleToRange([10, 20, 30, 40, 50], 0, 100)\n * // [0, 25, 50, 75, 100]\n *\n * scaleToRange([1, 2, 3, 4, 5], 1, 5)\n * // [1, 2, 3, 4, 5] (already in range)\n *\n * scaleToRange([0, 0.5, 1], 0, 255)\n * // [0, 127.5, 255] (grayscale pixel values)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Convert arbitrary scores to 1-5 star rating\n * function convertToStarRating(scores: number[]): number[] {\n * const stars = scaleToRange(scores, 1, 5)\n * return stars.map(s => Math.round(s * 2) / 2) // Round to 0.5\n * }\n *\n * const reviewScores = [45, 67, 89, 92, 100]\n * convertToStarRating(reviewScores)\n * // [1, 2.5, 4, 4.5, 5]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Progress bar percentage\n * function calculateProgress(completedTasks: number[]): number[] {\n * return scaleToRange(completedTasks, 0, 100).map(p => Math.round(p))\n * }\n *\n * const tasksCompleted = [2, 5, 8, 10]\n * calculateProgress(tasksCompleted)\n * // [0, 38, 75, 100] (percentage progress)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Audio normalization to [-1, 1] range\n * function normalizeAudioSamples(samples: number[]): Float32Array {\n * const normalized = scaleToRange(samples, -1, 1)\n * return new Float32Array(normalized)\n * }\n *\n * const audioData = [0, 1000, 2000, 3000, 4000]\n * normalizeAudioSamples(audioData)\n * // Float32Array [-1, -0.5, 0, 0.5, 1]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sensor calibration to voltage range\n * interface SensorReading {\n * timestamp: Date\n * rawValue: number\n * }\n *\n * function calibrateSensor(readings: SensorReading[]): number[] {\n * const rawValues = readings.map(r => r.rawValue)\n * // Calibrate to 0-5V range\n * return scaleToRange(rawValues, 0, 5)\n * }\n *\n * const sensorData = [\n * { timestamp: new Date(), rawValue: 100 },\n * { timestamp: new Date(), rawValue: 300 },\n * { timestamp: new Date(), rawValue: 500 }\n * ]\n * calibrateSensor(sensorData)\n * // [0, 2.5, 5] volts\n * ```\n *\n * @see {@link normalizeToRange} for [0, 1] normalization\n */\nexport const scaleToRange = (values: number[], minRange: number, maxRange: number): number[] => {\n const normalized = normalizeToRange(values)\n const scale = maxRange - minRange\n\n return normalized.map(value => minRange + value * scale)\n}\n\n/**\n * Calculates histogram by dividing data into equal-width bins\n *\n * Groups values into intervals (bins) and counts frequency in each bin.\n * Useful for understanding data distribution, finding patterns, and visualization.\n *\n * Algorithm:\n * 1. Find min/max values\n * 2. Calculate bin width: (max - min) / bins\n * 3. Create bins with ranges [start, end)\n * 4. Count values in each bin\n * 5. Last bin includes max value (closed interval)\n *\n * @param values - Array of numbers to analyze\n * @param bins - Number of bins/intervals to divide data into\n * @returns Array of objects with {range: [min, max], count: frequency}\n *\n * @example\n * ```typescript\n * // Basic histogram\n * const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n * calculateHistogram(data, 5)\n * // [\n * // { range: [1, 2.8], count: 2 },\n * // { range: [2.8, 4.6], count: 2 },\n * // { range: [4.6, 6.4], count: 2 },\n * // { range: [6.4, 8.2], count: 2 },\n * // { range: [8.2, 10], count: 2 }\n * // ]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Response time distribution analysis\n * function analyzeResponseTimes(times: number[]): void {\n * const histogram = calculateHistogram(times, 5)\n *\n * console.log('📊 Response Time Distribution:')\n * histogram.forEach(({ range, count }) => {\n * const bar = '█'.repeat(count)\n * console.log(`${range[0]}-${range[1]}ms: ${bar} (${count})`)\n * })\n *\n * // Identify slow requests\n * const slowBin = histogram[histogram.length - 1]\n * if (slowBin.count > histogram.length * 0.1) {\n * console.log(`⚠️ Warning: ${slowBin.count} requests in slowest bin`)\n * }\n * }\n *\n * const responseTimes = [\n * 120, 150, 180, 200, 220,\n * 250, 300, 350, 400, 5000\n * ]\n * analyzeResponseTimes(responseTimes)\n * // 120-1096ms: ████████ (8)\n * // ...\n * // 4024-5000ms: █ (1)\n * // ⚠️ Warning: 1 requests in slowest bin\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Salary distribution for HR analysis\n * interface Employee {\n * name: string\n * salary: number\n * }\n *\n * function analyzeSalaryDistribution(employees: Employee[]): void {\n * const salaries = employees.map(e => e.salary)\n * const histogram = calculateHistogram(salaries, 4)\n *\n * console.log('💰 Salary Distribution:')\n * histogram.forEach(({ range, count }, i) => {\n * const percentage = ((count / employees.length) * 100).toFixed(1)\n * console.log(`Band ${i + 1}: $${range[0].toLocaleString()}-$${range[1].toLocaleString()}`)\n * console.log(` Employees: ${count} (${percentage}%)`)\n * })\n * }\n *\n * const employees = [\n * { name: 'Alice', salary: 50000 },\n * { name: 'Bob', salary: 60000 },\n * { name: 'Charlie', salary: 75000 },\n * { name: 'David', salary: 90000 },\n * { name: 'Eve', salary: 120000 }\n * ]\n * analyzeSalaryDistribution(employees)\n * // Band 1: $50,000-$67,500 (2 employees - 40%)\n * // Band 2: $67,500-$85,000 (1 employee - 20%)\n * // ...\n * ```\n *\n * @see {@link calculatePercentile} for quantile analysis\n * @see {@link calculateQuartiles} for quartile-based binning\n */\nexport const calculateHistogram = (\n values: number[],\n bins: number\n): Array<{ range: [number, number]; count: number }> => {\n if (!values.length || bins <= 0) return []\n\n const min = Math.min(...values)\n const max = Math.max(...values)\n const binWidth = (max - min) / bins\n\n const histogram: Array<{ range: [number, number]; count: number }> = []\n\n for (let i = 0; i < bins; i++) {\n const rangeStart = min + i * binWidth\n const rangeEnd = i === bins - 1 ? max : rangeStart + binWidth\n\n const count = values.filter(\n value => value >= rangeStart && (i === bins - 1 ? value <= rangeEnd : value < rangeEnd)\n ).length\n\n histogram.push({\n range: [roundToDecimals(rangeStart, 2), roundToDecimals(rangeEnd, 2)],\n count,\n })\n }\n\n return histogram\n}\n\n// =============================================================================\n// BASIC MACHINE LEARNING UTILITIES\n// =============================================================================\n\n/**\n * Calculates Euclidean distance (straight-line distance) between two n-dimensional points\n *\n * Euclidean distance is the \"ordinary\" straight-line distance between two points.\n * Formula: √Σ(p1ᵢ - p2ᵢ)² for all dimensions\n *\n * Use cases:\n * - Machine learning (K-NN, K-Means clustering)\n * - Similarity measurement\n * - Computer vision (object detection)\n * - Geospatial calculations (2D/3D coordinates)\n *\n * @param point1 - First n-dimensional point [x, y, z, ...]\n * @param point2 - Second n-dimensional point [x, y, z, ...]\n * @returns Euclidean distance between the two points\n * @throws {Error} If points have different dimensions\n *\n * @example\n * ```typescript\n * // 2D distance (x, y coordinates)\n * calculateEuclideanDistance([0, 0], [3, 4]) // 5 (3-4-5 triangle)\n * calculateEuclideanDistance([1, 2], [4, 6]) // 5\n *\n * // 3D distance\n * calculateEuclideanDistance([0, 0, 0], [1, 1, 1]) // ~1.73 (√3)\n *\n * // High-dimensional (ML features)\n * calculateEuclideanDistance([1, 2, 3, 4], [2, 3, 4, 5]) // 2\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: K-Nearest Neighbors classification\n * interface User {\n * age: number\n * income: number\n * }\n *\n * function findNearestUsers(target: User, candidates: User[], k: number): User[] {\n * const distances = candidates.map(candidate => ({\n * user: candidate,\n * distance: calculateEuclideanDistance(\n * [target.age, target.income],\n * [candidate.age, candidate.income]\n * )\n * }))\n *\n * return distances\n * .sort((a, b) => a.distance - b.distance)\n * .slice(0, k)\n * .map(d => d.user)\n * }\n *\n * const target = { age: 30, income: 50000 }\n * const users = [\n * { age: 28, income: 48000 },\n * { age: 45, income: 80000 },\n * { age: 32, income: 52000 }\n * ]\n * findNearestUsers(target, users, 2)\n * // Returns 2 closest users by age/income\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Product recommendation similarity\n * interface Product {\n * price: number\n * rating: number\n * reviews: number\n * }\n *\n * function findSimilarProducts(\n * current: Product,\n * catalog: Product[]\n * ): Product[] {\n * const similarities = catalog.map(product => {\n * const distance = calculateEuclideanDistance(\n * [current.price, current.rating * 20, Math.log(current.reviews)],\n * [product.price, product.rating * 20, Math.log(product.reviews)]\n * )\n * return { product, similarity: 1 / (1 + distance) }\n * })\n *\n * return similarities\n * .sort((a, b) => b.similarity - a.similarity)\n * .slice(0, 5)\n * .map(s => s.product)\n * }\n * ```\n *\n * @see {@link calculateManhattanDistance} for taxicab distance (sum of absolute differences)\n * @see {@link simpleKMeans} for K-Means clustering using Euclidean distance\n */\nexport const calculateEuclideanDistance = (point1: number[], point2: number[]): number => {\n if (point1.length !== point2.length) {\n throw new Error('Points must have the same number of dimensions')\n }\n\n const squaredDiffs = point1.map((val, index) => Math.pow(val - point2[index], 2))\n return Math.sqrt(sum(squaredDiffs))\n}\n\n/**\n * Calculates Manhattan distance (taxicab/city block distance) between two n-dimensional points\n *\n * Manhattan distance is the sum of absolute differences in each dimension.\n * Formula: Σ|p1ᵢ - p2ᵢ| for all dimensions\n *\n * Named after Manhattan grid layout where you can only travel along streets (not diagonally).\n * Often more appropriate than Euclidean for grid-based movement or high-dimensional data.\n *\n * Use cases:\n * - Grid-based pathfinding (chess, robots)\n * - High-dimensional ML (less affected by curse of dimensionality)\n * - City distance calculations (street blocks)\n * - Outlier detection in sparse data\n *\n * @param point1 - First n-dimensional point [x, y, z, ...]\n * @param point2 - Second n-dimensional point [x, y, z, ...]\n * @returns Manhattan distance between the two points\n * @throws {Error} If points have different dimensions\n *\n * @example\n * ```typescript\n * // 2D Manhattan distance\n * calculateManhattanDistance([0, 0], [3, 4]) // 7 (3 + 4)\n * calculateManhattanDistance([1, 2], [4, 6]) // 7 (3 + 4)\n *\n * // Compare with Euclidean\n * calculateEuclideanDistance([0, 0], [3, 4]) // 5\n * calculateManhattanDistance([0, 0], [3, 4]) // 7\n *\n * // 3D distance\n * calculateManhattanDistance([0, 0, 0], [1, 1, 1]) // 3 (1+1+1)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: City block distance (taxi routing)\n * interface Location {\n * avenue: number // East-West\n * street: number // North-South\n * }\n *\n * function calculateTaxiFare(from: Location, to: Location): number {\n * const blocks = calculateManhattanDistance(\n * [from.avenue, from.street],\n * [to.avenue, to.street]\n * )\n * const baseFare = 3.50\n * const perBlock = 0.70\n * return baseFare + blocks * perBlock\n * }\n *\n * const start = { avenue: 5, street: 10 }\n * const end = { avenue: 12, street: 20 }\n * calculateTaxiFare(start, end)\n * // Blocks: 17, Fare: $15.40\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Chess king moves (Chebyshev) vs rook moves (Manhattan)\n * function calculateRookMoves(from: [number, number], to: [number, number]): number {\n * // Rook can move straight, so Manhattan distance = moves needed\n * return calculateManhattanDistance(from, to)\n * }\n *\n * calculateRookMoves([0, 0], [3, 4]) // 7 moves minimum\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: High-dimensional text similarity\n * function compareDocuments(doc1Vector: number[], doc2Vector: number[]): number {\n * // Manhattan often works better than Euclidean for sparse high-dim data\n * return calculateManhattanDistance(doc1Vector, doc2Vector)\n * }\n *\n * const doc1 = [0, 3, 0, 5, 0, 2] // Word frequency vector\n * const doc2 = [1, 2, 0, 4, 0, 3]\n * compareDocuments(doc1, doc2) // 5 (difference in word frequencies)\n * ```\n *\n * @see {@link calculateEuclideanDistance} for straight-line distance\n * @see {@link simpleKMeans} for clustering algorithm\n */\nexport const calculateManhattanDistance = (point1: number[], point2: number[]): number => {\n if (point1.length !== point2.length) {\n throw new Error('Points must have the same number of dimensions')\n }\n\n return sum(point1.map((val, index) => Math.abs(val - point2[index])))\n}\n\n/**\n * Implements simple K-Means clustering algorithm\n *\n * Groups data points into K clusters by minimizing within-cluster variance.\n * Uses Euclidean distance and iterative centroid updates until convergence.\n *\n * Algorithm:\n * 1. Initialize K centroids randomly from data points\n * 2. Assign each point to nearest centroid (Euclidean distance)\n * 3. Recalculate centroids as mean of assigned points\n * 4. Repeat steps 2-3 until convergence or max iterations\n *\n * Limitations:\n * - Requires knowing K in advance\n * - Sensitive to initial centroid placement (random)\n * - Assumes spherical clusters\n * - Can get stuck in local minima\n *\n * @param points - Array of n-dimensional points to cluster\n * @param k - Number of clusters to create\n * @param maxIterations - Maximum iterations before stopping (default: 100)\n * @returns Object with {centroids: K cluster centers, clusters: array mapping point index → cluster ID}\n *\n * @example\n * ```typescript\n * // Basic 2D clustering\n * const points = [\n * [1, 1], [2, 1], [1, 2], // Cluster 1 (bottom-left)\n * [8, 8], [9, 8], [8, 9] // Cluster 2 (top-right)\n * ]\n *\n * const { centroids, clusters } = simpleKMeans(points, 2)\n * console.log(centroids) // [[1.33, 1.33], [8.33, 8.33]]\n * console.log(clusters) // [0, 0, 0, 1, 1, 1]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Customer segmentation\n * interface Customer {\n * age: number\n * income: number\n * spendingScore: number\n * }\n *\n * function segmentCustomers(customers: Customer[], segments: number) {\n * const points = customers.map(c => [c.age, c.income / 1000, c.spendingScore])\n * const { centroids, clusters } = simpleKMeans(points, segments)\n *\n * const segmented = customers.map((customer, i) => ({\n * ...customer,\n * segment: clusters[i]\n * }))\n *\n * console.log('📊 Customer Segments:')\n * centroids.forEach((centroid, i) => {\n * const count = clusters.filter(c => c === i).length\n * console.log(`Segment ${i + 1}: ${count} customers`)\n * console.log(` Avg age: ${centroid[0].toFixed(1)}`)\n * console.log(` Avg income: $${(centroid[1] * 1000).toLocaleString()}`)\n * console.log(` Avg spending: ${centroid[2].toFixed(1)}/100`)\n * })\n *\n * return segmented\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Image color quantization (reduce colors)\n * function quantizeColors(pixels: [number, number, number][], colors: number) {\n * // Each pixel is [R, G, B]\n * const { centroids, clusters } = simpleKMeans(pixels, colors)\n *\n * // Replace each pixel with its cluster centroid color\n * return pixels.map((_, i) => {\n * const cluster = clusters[i]\n * return centroids[cluster].map(Math.round) as [number, number, number]\n * })\n * }\n *\n * // Reduce 16M colors to 8 dominant colors\n * const pixels: [number, number, number][] = [\n * [255, 100, 50], [250, 110, 55], // Similar reds\n * [50, 200, 100], [55, 210, 105] // Similar greens\n * ]\n * quantizeColors(pixels, 2)\n * // Groups similar colors into 2 clusters\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Anomaly detection in server metrics\n * interface ServerMetrics {\n * cpuUsage: number // 0-100%\n * memoryUsage: number // 0-100%\n * responseTime: number // ms\n * }\n *\n * function detectAnomalies(metrics: ServerMetrics[]): number[] {\n * const points = metrics.map(m => [\n * m.cpuUsage,\n * m.memoryUsage,\n * m.responseTime / 10 // Scale to similar range\n * ])\n *\n * const { centroids, clusters } = simpleKMeans(points, 3)\n *\n * // Find cluster with highest avg response time\n * const clusterAvgs = centroids.map(c => c[2] * 10)\n * const anomalyCluster = clusterAvgs.indexOf(Math.max(...clusterAvgs))\n *\n * // Return indices of anomalous metrics\n * return clusters\n * .map((cluster, i) => cluster === anomalyCluster ? i : -1)\n * .filter(i => i !== -1)\n * }\n * ```\n *\n * @see {@link calculateEuclideanDistance} for distance metric used\n * @see {@link normalizeToRange} for feature scaling before clustering\n */\nexport const simpleKMeans = (\n points: number[][],\n k: number,\n maxIterations = 100\n): { centroids: number[][]; clusters: number[] } => {\n if (points.length === 0 || k <= 0) {\n return { centroids: [], clusters: [] }\n }\n\n const dimensions = points[0].length\n\n // Initialize centroids randomly\n let centroids: number[][] = []\n for (let i = 0; i < k; i++) {\n const randomPoint = points[Math.floor(Math.random() * points.length)]\n centroids.push([...randomPoint])\n }\n\n const clusters: number[] = new Array(points.length)\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n let hasChanged = false\n\n // Assign points to clusters\n for (let i = 0; i < points.length; i++) {\n let minDistance = Infinity\n let closestCentroid = 0\n\n for (let j = 0; j < centroids.length; j++) {\n const distance = calculateEuclideanDistance(points[i], centroids[j])\n if (distance < minDistance) {\n minDistance = distance\n closestCentroid = j\n }\n }\n\n if (clusters[i] !== closestCentroid) {\n hasChanged = true\n clusters[i] = closestCentroid\n }\n }\n\n // Update centroids\n const newCentroids: number[][] = new Array(k).fill(0).map(() => new Array(dimensions).fill(0))\n const clusterCounts: number[] = new Array(k).fill(0)\n\n for (let i = 0; i < points.length; i++) {\n const cluster = clusters[i]\n clusterCounts[cluster]++\n\n for (let dim = 0; dim < dimensions; dim++) {\n newCentroids[cluster][dim] += points[i][dim]\n }\n }\n\n for (let i = 0; i < k; i++) {\n if (clusterCounts[i] > 0) {\n for (let dim = 0; dim < dimensions; dim++) {\n newCentroids[i][dim] /= clusterCounts[i]\n }\n }\n }\n\n centroids = newCentroids\n\n if (!hasChanged) break\n }\n\n return { centroids, clusters }\n}\n","/**\n * Number utilities\n */\n\n/**\n * Verifica si un valor es numéricamente válido o convertible a número.\n * Acepta números y cadenas que representan números válidos.\n * @param value - El valor a verificar.\n * @returns true si el valor es numéricamente válido, false en caso contrario.\n * @example\n * ```ts\n * isNumericValue(5) // true\n * isNumericValue(\"5\") // true\n * isNumericValue(\"12.34\") // true\n * isNumericValue(\"-42\") // true\n * isNumericValue(\"abc\") // false\n * isNumericValue(\"\") // false\n * isNumericValue(\" \") // false\n * isNumericValue(null) // false\n * isNumericValue(undefined) // false\n * isNumericValue(NaN) // false\n * isNumericValue(Infinity) // false\n * ```\n */\nexport function isNumericValue(value: any): boolean {\n if (value === null || value === undefined) return false\n if (typeof value === 'number') return !isNaN(value) && isFinite(value)\n if (typeof value === 'string') return value.trim() !== '' && !isNaN(Number(value))\n return false\n}\n\n/**\n * Rounds a number to a specified number of decimal places\n * @param num - The number to round\n * @param decimals - Number of decimal places (default: 2)\n * @returns The rounded number\n * @example\n * ```ts\n * roundToDecimals(3.14159, 2) // 3.14\n * roundToDecimals(-2.7182, 3) // -2.718\n * ```\n */\nexport function roundToDecimals(num: number, decimals: number = 2): number {\n const factor = Math.pow(10, decimals)\n // Use sign-aware rounding to handle negative numbers correctly\n return num >= 0 ? Math.round(num * factor) / factor : -Math.round(Math.abs(num) * factor) / factor\n}\n","/**\n * Asynchronous utilities and operations\n * Consolidated from core/async module\n */\n\n/* eslint-disable no-await-in-loop */\n\nimport { TsHelpersError, TsHelpersErrorCode } from './errors'\n\n// =============================================================================\n// DELAY UTILITIES\n// =============================================================================\n\n/**\n * Creates an asynchronous delay for the specified number of milliseconds\n *\n * Pauses async execution without blocking the event loop. Uses Promise with setTimeout\n * internally to schedule resumption after the specified delay.\n *\n * Common use cases:\n * - Rate limiting API calls\n * - Retry delays with exponential backoff\n * - Animation/transition timing\n * - Polling intervals\n * - Debouncing operations\n *\n * @param ms - Milliseconds to sleep (delay duration)\n * @returns Promise that resolves after the specified delay\n *\n * @example\n * ```typescript\n * // Basic delay\n * console.log('Starting...')\n * await sleep(2000) // Wait 2 seconds\n * console.log('Done!')\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Rate-limited API calls\n * async function fetchAllUsers(userIds: string[]): Promise<User[]> {\n * const users: User[] = []\n *\n * for (const id of userIds) {\n * const user = await api.getUser(id)\n * users.push(user)\n *\n * // Rate limit: 100ms between requests (max 10 req/sec)\n * await sleep(100)\n * }\n *\n * return users\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Exponential backoff retry\n * async function fetchWithRetry(url: string, maxRetries = 3): Promise<Response> {\n * let lastError: Error | null = null\n *\n * for (let attempt = 0; attempt < maxRetries; attempt++) {\n * try {\n * return await fetch(url)\n * } catch (error) {\n * lastError = error as Error\n * const delay = Math.pow(2, attempt) * 1000 // 1s, 2s, 4s\n * console.log(`Retry ${attempt + 1}/${maxRetries} in ${delay}ms`)\n * await sleep(delay)\n * }\n * }\n *\n * throw lastError\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Polling with timeout\n * async function pollUntilReady(\n * checkFn: () => Promise<boolean>,\n * timeoutMs = 30000\n * ): Promise<boolean> {\n * const startTime = Date.now()\n *\n * while (Date.now() - startTime < timeoutMs) {\n * if (await checkFn()) {\n * return true\n * }\n * await sleep(1000) // Poll every second\n * }\n *\n * throw new Error('Timeout waiting for ready state')\n * }\n *\n * // Usage: Wait for service to be ready\n * await pollUntilReady(async () => {\n * const response = await fetch('/health')\n * return response.ok\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Animated progress bar\n * async function animateProgress(element: HTMLElement): Promise<void> {\n * for (let i = 0; i <= 100; i += 5) {\n * element.style.width = `${i}%`\n * await sleep(50) // 50ms per step = 1 second total\n * }\n * }\n * ```\n *\n * @see {@link wait} for alias with same functionality\n * @see {@link runBatch} for controlled concurrent execution\n */\nexport const sleep = (ms: number): Promise<void> => {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/**\n * Simple alias for sleep - Pauses execution for specified milliseconds\n *\n * Identical to {@link sleep}, provided for semantic clarity in code.\n * Use `wait` when the context emphasizes waiting for a condition or event.\n *\n * @param ms - Milliseconds to wait\n * @returns Promise that resolves after the specified delay\n *\n * @example\n * ```typescript\n * // Semantically clearer in some contexts\n * await wait(1000) // Wait 1 second before continuing\n *\n * // vs sleep (implies intentional delay)\n * await sleep(1000) // Sleep for 1 second\n * ```\n *\n * @see {@link sleep} for full documentation and examples\n */\nexport const wait = (ms: number): Promise<void> => sleep(ms)\n\n// =============================================================================\n// BATCH PROCESSING\n// =============================================================================\n\n/**\n * Executes an array of Promises in batches to control concurrency\n *\n * Processes promises in sequential batches, waiting for each batch to complete before\n * starting the next. Prevents overwhelming systems with too many concurrent requests.\n *\n * Algorithm:\n * 1. Divide promises into batches of size `batchSize`\n * 2. Execute each batch with Promise.all (parallel within batch)\n * 3. Wait for batch completion before starting next batch\n * 4. Collect and return all results in original order\n *\n * Use cases:\n * - Rate-limited API calls (respect API quotas)\n * - Database bulk operations (avoid connection pool exhaustion)\n * - File system operations (prevent file descriptor limits)\n * - Memory-intensive operations (control memory usage)\n *\n * @param jobs - Array of Promises to execute\n * @param batchSize - Number of promises to execute concurrently per batch (default: 50)\n * @returns Promise resolving to array of all results in original order\n *\n * @example\n * ```typescript\n * // Basic batch processing\n * const urls = ['url1', 'url2', ..., 'url100'] // 100 URLs\n * const fetchPromises = urls.map(url => fetch(url))\n *\n * // Execute 10 at a time instead of all 100 simultaneously\n * const responses = await runBatch(fetchPromises, 10)\n * // Batch 1: urls 0-9 (parallel)\n * // Batch 2: urls 10-19 (parallel) - starts after batch 1 completes\n * // ... 10 batches total\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Bulk user data fetch respecting API rate limits\n * async function fetchUsersInBatches(userIds: string[]): Promise<User[]> {\n * console.log(`Fetching ${userIds.length} users in batches of 20...`)\n *\n * const fetchPromises = userIds.map(id =>\n * fetch(`/api/users/${id}`).then(res => res.json())\n * )\n *\n * const users = await runBatch(fetchPromises, 20)\n *\n * console.log(`✅ Fetched ${users.length} users`)\n * return users\n * }\n *\n * // Fetches 1000 users: 50 batches of 20, not 1000 simultaneous requests\n * const allUsers = await fetchUsersInBatches(userIdArray)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Database bulk insert with connection pool limits\n * async function bulkInsertUsers(users: User[]): Promise<void> {\n * // Database pool has 10 connections, use batch size of 5 for safety\n * const insertPromises = users.map(user =>\n * db.query('INSERT INTO users VALUES ($1, $2)', [user.name, user.email])\n * )\n *\n * await runBatch(insertPromises, 5)\n * console.log(`✅ Inserted ${users.length} users`)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Image processing pipeline\n * async function processImages(imagePaths: string[]): Promise<Buffer[]> {\n * console.log(`Processing ${imagePaths.length} images...`)\n *\n * const processingPromises = imagePaths.map(async path => {\n * const img = await loadImage(path)\n * const resized = await resize(img, { width: 800, height: 600 })\n * const compressed = await compress(resized, { quality: 80 })\n * return compressed\n * })\n *\n * // Process 3 images at a time to avoid memory exhaustion\n * const processed = await runBatch(processingPromises, 3)\n *\n * console.log(`✅ Processed ${processed.length} images`)\n * return processed\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Parallel file uploads with progress tracking\n * async function uploadFilesWithProgress(\n * files: File[]\n * ): Promise<UploadResult[]> {\n * let completed = 0\n *\n * const uploadPromises = files.map(async file => {\n * const result = await uploadToS3(file)\n * completed++\n * console.log(`Progress: ${completed}/${files.length} (${((completed/files.length)*100).toFixed(1)}%)`)\n * return result\n * })\n *\n * // Upload 5 files at a time\n * return await runBatch(uploadPromises, 5)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Scraping with politeness delay\n * async function scrapeWebsites(urls: string[]): Promise<ScrapedData[]> {\n * const scrapePromises = urls.map(async url => {\n * const html = await fetch(url).then(r => r.text())\n * const data = parseHTML(html)\n *\n * // Polite delay between requests in same batch\n * await sleep(200)\n *\n * return data\n * })\n *\n * // Only 3 concurrent requests to avoid overwhelming target server\n * return await runBatch(scrapePromises, 3)\n * }\n * ```\n *\n * @see {@link sleep} for adding delays between operations\n * @see {@link handleOperation} for dynamic operation execution\n */\nexport async function runBatch<T>(jobs: Promise<T>[], batchSize: number = 50): Promise<T[]> {\n if (batchSize <= 0) {\n throw new TsHelpersError('Batch size must be greater than 0', {\n code: TsHelpersErrorCode.INVALID_OPERATION,\n data: { batchSize },\n })\n }\n\n const results: T[] = []\n const batches = Math.ceil(jobs.length / batchSize)\n\n for (let i = 0; i < batches; i++) {\n const batchStart = i * batchSize\n const batchEnd = batchStart + batchSize\n const batch = jobs.slice(batchStart, batchEnd)\n\n const batchResults = await Promise.all(batch.map(job => job))\n results.push(...batchResults)\n }\n\n return results\n}\n\n// =============================================================================\n// DYNAMIC OPERATION UTILITIES\n// =============================================================================\n\n/**\n * Dynamically executes an operation on a target object by name\n *\n * Invokes methods on objects using string-based operation names. Supports nested\n * method access using 'parent/child' slash notation for organized operation namespacing.\n *\n * Features:\n * - Dynamic method invocation by string name\n * - Nested method access with '/' separator (e.g., 'api/getUser')\n * - Automatic error handling with descriptive messages\n * - Type-safe return value with generics\n *\n * Use cases:\n * - Dynamic API route handlers\n * - Plugin architectures with string-based commands\n * - RPC (Remote Procedure Call) implementations\n * - Command pattern implementations\n * - Configuration-driven operations\n *\n * @param target - Object containing methods to execute\n * @param operation - Method name or 'parent/child' path to execute\n * @param args - Arguments to pass to the operation\n * @returns Promise resolving to operation result\n * @throws {TsHelpersError} If operation doesn't exist on target\n *\n * @example\n * ```typescript\n * // Basic operation execution\n * const api = {\n * getUser: async (id: string) => ({ id, name: 'John' }),\n * createUser: async (data: any) => ({ id: '123', ...data })\n * }\n *\n * const user = await handleOperation<User>(api, 'getUser', 'user-123')\n * // { id: 'user-123', name: 'John' }\n * ```\n *\n * @example\n * ```typescript\n * // Nested operations with slash notation\n * const service = {\n * users: {\n * list: async () => [{ id: '1' }, { id: '2' }],\n * create: async (data: any) => ({ id: 'new', ...data }),\n * delete: async (id: string) => ({ success: true })\n * },\n * posts: {\n * list: async () => [{ id: 'post-1' }],\n * create: async (data: any) => ({ id: 'new-post', ...data })\n * }\n * }\n *\n * // Execute nested operation\n * const users = await handleOperation(service, 'users/list')\n * const newUser = await handleOperation(service, 'users/create', { name: 'Alice' })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Dynamic API router\n * interface ApiRequest {\n * operation: string\n * params: any[]\n * }\n *\n * const apiHandlers = {\n * user: {\n * get: async (id: string) => db.users.findById(id),\n * create: async (data: UserInput) => db.users.create(data),\n * update: async (id: string, data: Partial<UserInput>) =>\n * db.users.update(id, data),\n * delete: async (id: string) => db.users.delete(id)\n * },\n * product: {\n * search: async (query: string) => db.products.search(query),\n * list: async (page: number) => db.products.list(page)\n * }\n * }\n *\n * async function handleApiRequest(req: ApiRequest): Promise<any> {\n * try {\n * return await handleOperation(\n * apiHandlers,\n * req.operation,\n * ...req.params\n * )\n * } catch (error) {\n * console.error(`Failed to execute ${req.operation}:`, error)\n * throw error\n * }\n * }\n *\n * // Usage\n * await handleApiRequest({ operation: 'user/get', params: ['user-123'] })\n * await handleApiRequest({ operation: 'product/search', params: ['laptop'] })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Plugin system with dynamic commands\n * interface Plugin {\n * name: string\n * commands: Record<string, (...args: any[]) => Promise<any>>\n * }\n *\n * class PluginManager {\n * private plugins: Map<string, Plugin> = new Map()\n *\n * register(plugin: Plugin): void {\n * this.plugins.set(plugin.name, plugin)\n * }\n *\n * async executeCommand(\n * pluginName: string,\n * command: string,\n * ...args: any[]\n * ): Promise<any> {\n * const plugin = this.plugins.get(pluginName)\n * if (!plugin) throw new Error(`Plugin ${pluginName} not found`)\n *\n * return handleOperation(plugin.commands, command, ...args)\n * }\n * }\n *\n * // Register plugins\n * const manager = new PluginManager()\n * manager.register({\n * name: 'fileOps',\n * commands: {\n * read: async (path: string) => fs.readFile(path, 'utf-8'),\n * write: async (path: string, content: string) =>\n * fs.writeFile(path, content)\n * }\n * })\n *\n * // Execute plugin commands dynamically\n * await manager.executeCommand('fileOps', 'read', './config.json')\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: RPC-style service calls\n * const rpcService = {\n * math: {\n * add: async (a: number, b: number) => a + b,\n * multiply: async (a: number, b: number) => a * b\n * },\n * string: {\n * reverse: async (s: string) => s.split('').reverse().join(''),\n * uppercase: async (s: string) => s.toUpperCase()\n * }\n * }\n *\n * async function rpcCall(method: string, ...params: any[]): Promise<any> {\n * console.log(`RPC Call: ${method}(${params.join(', ')})`)\n * const result = await handleOperation(rpcService, method, ...params)\n * console.log(`RPC Result: ${result}`)\n * return result\n * }\n *\n * await rpcCall('math/add', 5, 3) // RPC Result: 8\n * await rpcCall('string/reverse', 'hello') // RPC Result: olleh\n * ```\n *\n * @example\n * ```typescript\n * // Error handling\n * try {\n * await handleOperation(api, 'nonexistent/method')\n * } catch (error) {\n * console.error(error.message)\n * // \"Operation [nonexistent/method] does not exist\"\n * console.error(error.code)\n * // TsHelpersErrorCode.INVALID_OPERATION\n * }\n * ```\n *\n * @see {@link TsHelpersError} for error structure\n * @see {@link TsHelpersErrorCode} for error codes\n */\nexport function handleOperation<T>(\n target: Record<string, any>,\n operation: string,\n ...args: any[]\n): Promise<T> {\n if (operation.includes('/')) {\n const [parentOp, childOp] = operation.split('/')\n\n if (!target[parentOp] || !target[parentOp][childOp]) {\n throw new TsHelpersError(`Operation [${operation}] does not exist`, {\n code: TsHelpersErrorCode.INVALID_OPERATION,\n data: { operation, parentOp, childOp },\n })\n }\n\n return target[parentOp][childOp](...args)\n }\n\n if (!target[operation]) {\n throw new TsHelpersError(`Operation [${operation}] does not exist`, {\n code: TsHelpersErrorCode.INVALID_OPERATION,\n data: { operation },\n })\n }\n\n return target[operation](...args)\n}\n","/**\n * Error handling utilities with specific error types and codes\n * Provides structured error handling for validation, data processing, and environment issues\n */\n\n/**\n * Enumeration of specific error codes for different failure scenarios\n * @example\n * ```ts\n * // Using error codes for type-safe error handling\n * try {\n * validateNIF('invalid')\n * } catch (error) {\n * if (error.code === TsHelpersErrorCode.VALIDATION_FAILED) {\n * console.log('Validation error:', error.data)\n * }\n * }\n * ```\n */\nexport enum TsHelpersErrorCode {\n /** Validation of input data failed (NIF, email, etc.) */\n VALIDATION_FAILED = 'VALIDATION_FAILED',\n /** Error processing data (CSV, JSON, aggregations, etc.) */\n DATA_PROCESSING_FAILED = 'DATA_PROCESSING_FAILED',\n /** Current environment doesn't support the operation */\n ENVIRONMENT_NOT_SUPPORTED = 'ENVIRONMENT_NOT_SUPPORTED',\n /** File format not supported for import/export */\n UNSUPPORTED_FORMAT = 'UNSUPPORTED_FORMAT',\n /** File system operation failed */\n FILE_ERROR = 'FILE_ERROR',\n /** Network or fetch operation failed */\n NETWORK_ERROR = 'NETWORK_ERROR',\n /** Invalid operation or function call */\n INVALID_OPERATION = 'INVALID_OPERATION',\n /** Crypto operation failed (hash, token generation) */\n CRYPTO_ERROR = 'CRYPTO_ERROR',\n /** Math calculation failed (invalid input, division by zero) */\n MATH_ERROR = 'MATH_ERROR',\n /** Generic unknown error */\n UNKNOWN_ERROR = 'UNKNOWN_ERROR',\n}\n\n/**\n * Options for creating TsHelpersError instances\n */\nexport interface TsHelpersErrorOptions {\n /** Specific error code for categorization */\n code?: TsHelpersErrorCode\n /** Additional data about the error context */\n data?: any\n /** Original error that caused this error */\n cause?: Error\n}\n\n/**\n * Main error class for @g10/ts-helpers with structured error information\n * @example\n * ```ts\n * // Creating structured errors\n * throw new TsHelpersError('Invalid NIF format', {\n * code: TsHelpersErrorCode.VALIDATION_FAILED,\n * data: { input: '12345', expected: '8 digits + letter' }\n * })\n *\n * // Error handling with type checking\n * try {\n * someOperation()\n * } catch (error) {\n * if (error instanceof TsHelpersError) {\n * console.log('Error code:', error.code)\n * console.log('Error data:', error.data)\n * }\n * }\n * ```\n */\nexport class TsHelpersError extends Error {\n public readonly code?: TsHelpersErrorCode\n public readonly data?: any\n public readonly cause?: Error\n\n constructor(message: string, options: TsHelpersErrorOptions = {}) {\n super(message)\n this.name = 'TsHelpersError'\n this.code = options.code\n this.data = options.data\n this.cause = options.cause\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TsHelpersError)\n }\n }\n}\n\n/**\n * Specialized error class for data processing operations\n * @example\n * ```ts\n * // Data processing errors\n * throw new DataError(\n * 'Failed to parse CSV',\n * TsHelpersErrorCode.DATA_PROCESSING_FAILED,\n * { line: 5, column: 'amount' }\n * )\n * ```\n */\nexport class DataError extends TsHelpersError {\n constructor(message: string, code?: TsHelpersErrorCode, data?: any) {\n super(message, { code, data })\n this.name = 'DataError'\n }\n}\n\n/**\n * Creates a validation error with structured information\n * @param message - Descriptive error message\n * @param field - Field name that failed validation\n * @param value - Value that failed validation\n * @returns TsHelpersError with validation context\n * @example\n * ```ts\n * // Using in validation functions\n * if (!isValidEmail(email)) {\n * throw createValidationError('Invalid email format', 'email', email)\n * }\n *\n * // Error contains structured data\n * // error.code === TsHelpersErrorCode.VALIDATION_FAILED\n * // error.data === { field: 'email', value: 'invalid-email' }\n * ```\n */\nexport function createValidationError(message: string, field: string, value: any): TsHelpersError {\n return new TsHelpersError(`Validation failed: ${message}`, {\n code: TsHelpersErrorCode.VALIDATION_FAILED,\n data: { field, value },\n })\n}\n\n/**\n * Creates a crypto operation error\n * @param message - Descriptive error message\n * @param operation - Crypto operation that failed\n * @param details - Additional error details\n * @returns TsHelpersError with crypto context\n * @example\n * ```ts\n * // Using in crypto functions\n * if (!crypto.getRandomValues) {\n * throw createCryptoError('Web Crypto API not available', 'generateSecureToken', {\n * environment: 'browser',\n * fallback: 'Math.random'\n * })\n * }\n * ```\n */\nexport function createCryptoError(\n message: string,\n operation: string,\n details?: any\n): TsHelpersError {\n return new TsHelpersError(`Crypto error: ${message}`, {\n code: TsHelpersErrorCode.CRYPTO_ERROR,\n data: { operation, details },\n })\n}\n\n/**\n * Creates a math calculation error\n * @param message - Descriptive error message\n * @param operation - Math operation that failed\n * @param input - Input data that caused the error\n * @returns TsHelpersError with math context\n * @example\n * ```ts\n * // Using in math functions\n * if (values.length === 0) {\n * throw createMathError('Cannot calculate median of empty array', 'calculateMedian', values)\n * }\n * ```\n */\nexport function createMathError(message: string, operation: string, input?: any): TsHelpersError {\n return new TsHelpersError(`Math error: ${message}`, {\n code: TsHelpersErrorCode.MATH_ERROR,\n data: { operation, input },\n })\n}\n"],"mappings":"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","names":["sum","g","validator","crypto","dayjs","utc","relativeTime","weekOfYearPlugin","customParseFormat","isSameOrAfter","isSameOrBefore","weekday","localeData","localizedFormat","format","dayOfWeek","fastEqual","crc32","lodash","lodash","sum"]}