@fluixi/utils 1.0.0-alpha.53

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 (354) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/index.cjs +1 -0
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +1 -0
  7. package/dist/index.mjs +1 -0
  8. package/dist/lib/array/advanced.cjs +1 -0
  9. package/dist/lib/array/advanced.d.ts +1116 -0
  10. package/dist/lib/array/advanced.d.ts.map +1 -0
  11. package/dist/lib/array/advanced.js +2429 -0
  12. package/dist/lib/array/advanced.mjs +1 -0
  13. package/dist/lib/array/array.cjs +1 -0
  14. package/dist/lib/array/array.d.ts +6 -0
  15. package/dist/lib/array/array.d.ts.map +1 -0
  16. package/dist/lib/array/array.js +31 -0
  17. package/dist/lib/array/array.mjs +1 -0
  18. package/dist/lib/array/index.cjs +1 -0
  19. package/dist/lib/array/index.d.ts +4 -0
  20. package/dist/lib/array/index.d.ts.map +1 -0
  21. package/dist/lib/array/index.js +3 -0
  22. package/dist/lib/array/index.mjs +1 -0
  23. package/dist/lib/array/utils.cjs +1 -0
  24. package/dist/lib/array/utils.d.ts +100 -0
  25. package/dist/lib/array/utils.d.ts.map +1 -0
  26. package/dist/lib/array/utils.js +165 -0
  27. package/dist/lib/array/utils.mjs +1 -0
  28. package/dist/lib/color/color.cjs +1 -0
  29. package/dist/lib/color/color.d.ts +366 -0
  30. package/dist/lib/color/color.d.ts.map +1 -0
  31. package/dist/lib/color/color.js +722 -0
  32. package/dist/lib/color/color.mjs +1 -0
  33. package/dist/lib/color/constants.cjs +1 -0
  34. package/dist/lib/color/constants.d.ts +361 -0
  35. package/dist/lib/color/constants.d.ts.map +1 -0
  36. package/dist/lib/color/constants.js +358 -0
  37. package/dist/lib/color/constants.mjs +1 -0
  38. package/dist/lib/color/conversions.cjs +1 -0
  39. package/dist/lib/color/conversions.d.ts +166 -0
  40. package/dist/lib/color/conversions.d.ts.map +1 -0
  41. package/dist/lib/color/conversions.js +766 -0
  42. package/dist/lib/color/conversions.mjs +1 -0
  43. package/dist/lib/color/helpers.cjs +1 -0
  44. package/dist/lib/color/helpers.d.ts +75 -0
  45. package/dist/lib/color/helpers.d.ts.map +1 -0
  46. package/dist/lib/color/helpers.js +419 -0
  47. package/dist/lib/color/helpers.mjs +1 -0
  48. package/dist/lib/color/index.cjs +1 -0
  49. package/dist/lib/color/index.d.ts +12 -0
  50. package/dist/lib/color/index.d.ts.map +1 -0
  51. package/dist/lib/color/index.js +15 -0
  52. package/dist/lib/color/index.mjs +1 -0
  53. package/dist/lib/color/types.cjs +1 -0
  54. package/dist/lib/color/types.d.ts +179 -0
  55. package/dist/lib/color/types.d.ts.map +1 -0
  56. package/dist/lib/color/types.js +1 -0
  57. package/dist/lib/color/types.mjs +0 -0
  58. package/dist/lib/color/utils.cjs +1 -0
  59. package/dist/lib/color/utils.d.ts +199 -0
  60. package/dist/lib/color/utils.d.ts.map +1 -0
  61. package/dist/lib/color/utils.js +858 -0
  62. package/dist/lib/color/utils.mjs +1 -0
  63. package/dist/lib/compare/comparators.cjs +1 -0
  64. package/dist/lib/compare/comparators.d.ts +65 -0
  65. package/dist/lib/compare/comparators.d.ts.map +1 -0
  66. package/dist/lib/compare/comparators.js +210 -0
  67. package/dist/lib/compare/comparators.mjs +1 -0
  68. package/dist/lib/compare/index.cjs +1 -0
  69. package/dist/lib/compare/index.d.ts +2 -0
  70. package/dist/lib/compare/index.d.ts.map +1 -0
  71. package/dist/lib/compare/index.js +1 -0
  72. package/dist/lib/compare/index.mjs +1 -0
  73. package/dist/lib/crypto/hash.cjs +1 -0
  74. package/dist/lib/crypto/hash.d.ts +6 -0
  75. package/dist/lib/crypto/hash.d.ts.map +1 -0
  76. package/dist/lib/crypto/hash.js +53 -0
  77. package/dist/lib/crypto/hash.mjs +1 -0
  78. package/dist/lib/crypto/index.cjs +1 -0
  79. package/dist/lib/crypto/index.d.ts +2 -0
  80. package/dist/lib/crypto/index.d.ts.map +1 -0
  81. package/dist/lib/crypto/index.js +1 -0
  82. package/dist/lib/crypto/index.mjs +1 -0
  83. package/dist/lib/dom/events.cjs +1 -0
  84. package/dist/lib/dom/events.d.ts +159 -0
  85. package/dist/lib/dom/events.d.ts.map +1 -0
  86. package/dist/lib/dom/events.js +50 -0
  87. package/dist/lib/dom/events.mjs +1 -0
  88. package/dist/lib/dom/index.cjs +1 -0
  89. package/dist/lib/dom/index.d.ts +3 -0
  90. package/dist/lib/dom/index.d.ts.map +1 -0
  91. package/dist/lib/dom/index.js +2 -0
  92. package/dist/lib/dom/index.mjs +1 -0
  93. package/dist/lib/dom/utils.cjs +1 -0
  94. package/dist/lib/dom/utils.d.ts +6 -0
  95. package/dist/lib/dom/utils.d.ts.map +1 -0
  96. package/dist/lib/dom/utils.js +37 -0
  97. package/dist/lib/dom/utils.mjs +1 -0
  98. package/dist/lib/functions/functions.cjs +1 -0
  99. package/dist/lib/functions/functions.d.ts +329 -0
  100. package/dist/lib/functions/functions.d.ts.map +1 -0
  101. package/dist/lib/functions/functions.js +585 -0
  102. package/dist/lib/functions/functions.mjs +1 -0
  103. package/dist/lib/functions/index.cjs +1 -0
  104. package/dist/lib/functions/index.d.ts +3 -0
  105. package/dist/lib/functions/index.d.ts.map +1 -0
  106. package/dist/lib/functions/index.js +1 -0
  107. package/dist/lib/functions/index.mjs +1 -0
  108. package/dist/lib/functions/types.cjs +1 -0
  109. package/dist/lib/functions/types.d.ts +2 -0
  110. package/dist/lib/functions/types.d.ts.map +1 -0
  111. package/dist/lib/functions/types.js +1 -0
  112. package/dist/lib/functions/types.mjs +0 -0
  113. package/dist/lib/helpers.cjs +1 -0
  114. package/dist/lib/helpers.d.ts +13 -0
  115. package/dist/lib/helpers.d.ts.map +1 -0
  116. package/dist/lib/helpers.js +66 -0
  117. package/dist/lib/helpers.mjs +1 -0
  118. package/dist/lib/index.cjs +1 -0
  119. package/dist/lib/index.d.ts +6 -0
  120. package/dist/lib/index.d.ts.map +1 -0
  121. package/dist/lib/index.js +8 -0
  122. package/dist/lib/index.mjs +1 -0
  123. package/dist/lib/maths/constants.cjs +1 -0
  124. package/dist/lib/maths/constants.d.ts +84 -0
  125. package/dist/lib/maths/constants.d.ts.map +1 -0
  126. package/dist/lib/maths/constants.js +79 -0
  127. package/dist/lib/maths/constants.mjs +1 -0
  128. package/dist/lib/maths/fn/advanced.cjs +1 -0
  129. package/dist/lib/maths/fn/advanced.d.ts +149 -0
  130. package/dist/lib/maths/fn/advanced.d.ts.map +1 -0
  131. package/dist/lib/maths/fn/advanced.js +264 -0
  132. package/dist/lib/maths/fn/advanced.mjs +1 -0
  133. package/dist/lib/maths/fn/basic.cjs +1 -0
  134. package/dist/lib/maths/fn/basic.d.ts +182 -0
  135. package/dist/lib/maths/fn/basic.d.ts.map +1 -0
  136. package/dist/lib/maths/fn/basic.js +343 -0
  137. package/dist/lib/maths/fn/basic.mjs +1 -0
  138. package/dist/lib/maths/fn/complex.cjs +1 -0
  139. package/dist/lib/maths/fn/complex.d.ts +153 -0
  140. package/dist/lib/maths/fn/complex.d.ts.map +1 -0
  141. package/dist/lib/maths/fn/complex.js +383 -0
  142. package/dist/lib/maths/fn/complex.mjs +1 -0
  143. package/dist/lib/maths/fn/index.cjs +1 -0
  144. package/dist/lib/maths/fn/index.d.ts +10 -0
  145. package/dist/lib/maths/fn/index.d.ts.map +1 -0
  146. package/dist/lib/maths/fn/index.js +9 -0
  147. package/dist/lib/maths/fn/index.mjs +1 -0
  148. package/dist/lib/maths/fn/trigo.cjs +1 -0
  149. package/dist/lib/maths/fn/trigo.d.ts +147 -0
  150. package/dist/lib/maths/fn/trigo.d.ts.map +1 -0
  151. package/dist/lib/maths/fn/trigo.js +227 -0
  152. package/dist/lib/maths/fn/trigo.mjs +1 -0
  153. package/dist/lib/maths/fn/vector.cjs +1 -0
  154. package/dist/lib/maths/fn/vector.d.ts +512 -0
  155. package/dist/lib/maths/fn/vector.d.ts.map +1 -0
  156. package/dist/lib/maths/fn/vector.js +1136 -0
  157. package/dist/lib/maths/fn/vector.mjs +1 -0
  158. package/dist/lib/maths/formatter.cjs +1 -0
  159. package/dist/lib/maths/formatter.d.ts +35 -0
  160. package/dist/lib/maths/formatter.d.ts.map +1 -0
  161. package/dist/lib/maths/formatter.js +56 -0
  162. package/dist/lib/maths/formatter.mjs +1 -0
  163. package/dist/lib/maths/guards.cjs +1 -0
  164. package/dist/lib/maths/guards.d.ts +166 -0
  165. package/dist/lib/maths/guards.d.ts.map +1 -0
  166. package/dist/lib/maths/guards.js +315 -0
  167. package/dist/lib/maths/guards.mjs +1 -0
  168. package/dist/lib/maths/index.cjs +1 -0
  169. package/dist/lib/maths/index.d.ts +24 -0
  170. package/dist/lib/maths/index.d.ts.map +1 -0
  171. package/dist/lib/maths/index.js +29 -0
  172. package/dist/lib/maths/index.mjs +1 -0
  173. package/dist/lib/maths/parser.cjs +1 -0
  174. package/dist/lib/maths/parser.d.ts +20 -0
  175. package/dist/lib/maths/parser.d.ts.map +1 -0
  176. package/dist/lib/maths/parser.js +78 -0
  177. package/dist/lib/maths/parser.mjs +1 -0
  178. package/dist/lib/maths/random.cjs +1 -0
  179. package/dist/lib/maths/random.d.ts +27 -0
  180. package/dist/lib/maths/random.d.ts.map +1 -0
  181. package/dist/lib/maths/random.js +49 -0
  182. package/dist/lib/maths/random.mjs +1 -0
  183. package/dist/lib/maths/types/advanced.cjs +1 -0
  184. package/dist/lib/maths/types/advanced.d.ts +357 -0
  185. package/dist/lib/maths/types/advanced.d.ts.map +1 -0
  186. package/dist/lib/maths/types/advanced.js +5 -0
  187. package/dist/lib/maths/types/advanced.mjs +0 -0
  188. package/dist/lib/maths/types/basic.cjs +1 -0
  189. package/dist/lib/maths/types/basic.d.ts +95 -0
  190. package/dist/lib/maths/types/basic.d.ts.map +1 -0
  191. package/dist/lib/maths/types/basic.js +5 -0
  192. package/dist/lib/maths/types/basic.mjs +0 -0
  193. package/dist/lib/maths/types/index.cjs +1 -0
  194. package/dist/lib/maths/types/index.d.ts +4 -0
  195. package/dist/lib/maths/types/index.d.ts.map +1 -0
  196. package/dist/lib/maths/types/index.js +3 -0
  197. package/dist/lib/maths/types/index.mjs +0 -0
  198. package/dist/lib/maths/types/negative.cjs +1 -0
  199. package/dist/lib/maths/types/negative.d.ts +51 -0
  200. package/dist/lib/maths/types/negative.d.ts.map +1 -0
  201. package/dist/lib/maths/types/negative.js +5 -0
  202. package/dist/lib/maths/types/negative.mjs +0 -0
  203. package/dist/lib/maths/types/operations.cjs +1 -0
  204. package/dist/lib/maths/types/operations.d.ts +188 -0
  205. package/dist/lib/maths/types/operations.d.ts.map +1 -0
  206. package/dist/lib/maths/types/operations.js +6 -0
  207. package/dist/lib/maths/types/operations.mjs +0 -0
  208. package/dist/lib/object/clone.cjs +1 -0
  209. package/dist/lib/object/clone.d.ts +46 -0
  210. package/dist/lib/object/clone.d.ts.map +1 -0
  211. package/dist/lib/object/clone.js +104 -0
  212. package/dist/lib/object/clone.mjs +1 -0
  213. package/dist/lib/object/diff.cjs +1 -0
  214. package/dist/lib/object/diff.d.ts +203 -0
  215. package/dist/lib/object/diff.d.ts.map +1 -0
  216. package/dist/lib/object/diff.js +805 -0
  217. package/dist/lib/object/diff.mjs +1 -0
  218. package/dist/lib/object/getter-setter.cjs +1 -0
  219. package/dist/lib/object/getter-setter.d.ts +361 -0
  220. package/dist/lib/object/getter-setter.d.ts.map +1 -0
  221. package/dist/lib/object/getter-setter.js +1771 -0
  222. package/dist/lib/object/getter-setter.mjs +1 -0
  223. package/dist/lib/object/index.cjs +6 -0
  224. package/dist/lib/object/index.d.ts +13 -0
  225. package/dist/lib/object/index.d.ts.map +1 -0
  226. package/dist/lib/object/index.js +12 -0
  227. package/dist/lib/object/index.mjs +6 -0
  228. package/dist/lib/object/merge.cjs +1 -0
  229. package/dist/lib/object/merge.d.ts +93 -0
  230. package/dist/lib/object/merge.d.ts.map +1 -0
  231. package/dist/lib/object/merge.js +474 -0
  232. package/dist/lib/object/merge.mjs +1 -0
  233. package/dist/lib/object/object.cjs +1 -0
  234. package/dist/lib/object/object.d.ts +128 -0
  235. package/dist/lib/object/object.d.ts.map +1 -0
  236. package/dist/lib/object/object.js +432 -0
  237. package/dist/lib/object/object.mjs +1 -0
  238. package/dist/lib/object/omit.cjs +1 -0
  239. package/dist/lib/object/omit.d.ts +351 -0
  240. package/dist/lib/object/omit.d.ts.map +1 -0
  241. package/dist/lib/object/omit.js +656 -0
  242. package/dist/lib/object/omit.mjs +1 -0
  243. package/dist/lib/object/reconcile.cjs +1 -0
  244. package/dist/lib/object/reconcile.d.ts +7 -0
  245. package/dist/lib/object/reconcile.d.ts.map +1 -0
  246. package/dist/lib/object/reconcile.js +122 -0
  247. package/dist/lib/object/reconcile.mjs +1 -0
  248. package/dist/lib/object/selector.cjs +1 -0
  249. package/dist/lib/object/selector.d.ts +50 -0
  250. package/dist/lib/object/selector.d.ts.map +1 -0
  251. package/dist/lib/object/selector.js +371 -0
  252. package/dist/lib/object/selector.mjs +1 -0
  253. package/dist/lib/object/sort.cjs +1 -0
  254. package/dist/lib/object/sort.d.ts +149 -0
  255. package/dist/lib/object/sort.d.ts.map +1 -0
  256. package/dist/lib/object/sort.js +298 -0
  257. package/dist/lib/object/sort.mjs +1 -0
  258. package/dist/lib/object/transform.cjs +1 -0
  259. package/dist/lib/object/transform.d.ts +620 -0
  260. package/dist/lib/object/transform.d.ts.map +1 -0
  261. package/dist/lib/object/transform.js +1058 -0
  262. package/dist/lib/object/transform.mjs +1 -0
  263. package/dist/lib/object/types.cjs +1 -0
  264. package/dist/lib/object/types.d.ts +250 -0
  265. package/dist/lib/object/types.d.ts.map +1 -0
  266. package/dist/lib/object/types.js +1 -0
  267. package/dist/lib/object/types.mjs +0 -0
  268. package/dist/lib/object/utils.cjs +6 -0
  269. package/dist/lib/object/utils.d.ts +165 -0
  270. package/dist/lib/object/utils.d.ts.map +1 -0
  271. package/dist/lib/object/utils.js +444 -0
  272. package/dist/lib/object/utils.mjs +6 -0
  273. package/dist/lib/primitive/boolean/boolean.cjs +1 -0
  274. package/dist/lib/primitive/boolean/boolean.d.ts +276 -0
  275. package/dist/lib/primitive/boolean/boolean.d.ts.map +1 -0
  276. package/dist/lib/primitive/boolean/boolean.js +615 -0
  277. package/dist/lib/primitive/boolean/boolean.mjs +1 -0
  278. package/dist/lib/primitive/boolean/index.cjs +1 -0
  279. package/dist/lib/primitive/boolean/index.d.ts +3 -0
  280. package/dist/lib/primitive/boolean/index.d.ts.map +1 -0
  281. package/dist/lib/primitive/boolean/index.js +2 -0
  282. package/dist/lib/primitive/boolean/index.mjs +1 -0
  283. package/dist/lib/primitive/boolean/types.cjs +1 -0
  284. package/dist/lib/primitive/boolean/types.d.ts +14 -0
  285. package/dist/lib/primitive/boolean/types.d.ts.map +1 -0
  286. package/dist/lib/primitive/boolean/types.js +1 -0
  287. package/dist/lib/primitive/boolean/types.mjs +0 -0
  288. package/dist/lib/primitive/date/date.cjs +1 -0
  289. package/dist/lib/primitive/date/date.d.ts +641 -0
  290. package/dist/lib/primitive/date/date.d.ts.map +1 -0
  291. package/dist/lib/primitive/date/date.js +1998 -0
  292. package/dist/lib/primitive/date/date.mjs +1 -0
  293. package/dist/lib/primitive/date/index.cjs +1 -0
  294. package/dist/lib/primitive/date/index.d.ts +3 -0
  295. package/dist/lib/primitive/date/index.d.ts.map +1 -0
  296. package/dist/lib/primitive/date/index.js +2 -0
  297. package/dist/lib/primitive/date/index.mjs +1 -0
  298. package/dist/lib/primitive/date/types.cjs +1 -0
  299. package/dist/lib/primitive/date/types.d.ts +205 -0
  300. package/dist/lib/primitive/date/types.d.ts.map +1 -0
  301. package/dist/lib/primitive/date/types.js +7 -0
  302. package/dist/lib/primitive/date/types.mjs +0 -0
  303. package/dist/lib/primitive/index.cjs +5 -0
  304. package/dist/lib/primitive/index.d.ts +5 -0
  305. package/dist/lib/primitive/index.d.ts.map +1 -0
  306. package/dist/lib/primitive/index.js +4 -0
  307. package/dist/lib/primitive/index.mjs +5 -0
  308. package/dist/lib/primitive/string/index.cjs +5 -0
  309. package/dist/lib/primitive/string/index.d.ts +3 -0
  310. package/dist/lib/primitive/string/index.d.ts.map +1 -0
  311. package/dist/lib/primitive/string/index.js +2 -0
  312. package/dist/lib/primitive/string/index.mjs +5 -0
  313. package/dist/lib/primitive/string/parser-2.cjs +8 -0
  314. package/dist/lib/primitive/string/parser-2.d.ts +17 -0
  315. package/dist/lib/primitive/string/parser-2.d.ts.map +1 -0
  316. package/dist/lib/primitive/string/parser-2.js +656 -0
  317. package/dist/lib/primitive/string/parser-2.mjs +8 -0
  318. package/dist/lib/primitive/string/parser.cjs +3 -0
  319. package/dist/lib/primitive/string/parser.d.ts +9 -0
  320. package/dist/lib/primitive/string/parser.d.ts.map +1 -0
  321. package/dist/lib/primitive/string/parser.js +775 -0
  322. package/dist/lib/primitive/string/parser.mjs +3 -0
  323. package/dist/lib/primitive/string/string.cjs +5 -0
  324. package/dist/lib/primitive/string/string.d.ts +535 -0
  325. package/dist/lib/primitive/string/string.d.ts.map +1 -0
  326. package/dist/lib/primitive/string/string.js +1301 -0
  327. package/dist/lib/primitive/string/string.mjs +5 -0
  328. package/dist/lib/primitive/string/types.cjs +1 -0
  329. package/dist/lib/primitive/string/types.d.ts +318 -0
  330. package/dist/lib/primitive/string/types.d.ts.map +1 -0
  331. package/dist/lib/primitive/string/types.js +5 -0
  332. package/dist/lib/primitive/string/types.mjs +0 -0
  333. package/dist/lib/primitive/types.cjs +1 -0
  334. package/dist/lib/primitive/types.d.ts +27 -0
  335. package/dist/lib/primitive/types.d.ts.map +1 -0
  336. package/dist/lib/primitive/types.js +1 -0
  337. package/dist/lib/primitive/types.mjs +0 -0
  338. package/dist/lib/url/index.cjs +1 -0
  339. package/dist/lib/url/index.d.ts +3 -0
  340. package/dist/lib/url/index.d.ts.map +1 -0
  341. package/dist/lib/url/index.js +2 -0
  342. package/dist/lib/url/index.mjs +1 -0
  343. package/dist/lib/url/parser.cjs +1 -0
  344. package/dist/lib/url/parser.d.ts +216 -0
  345. package/dist/lib/url/parser.d.ts.map +1 -0
  346. package/dist/lib/url/parser.js +488 -0
  347. package/dist/lib/url/parser.mjs +1 -0
  348. package/dist/lib/url/types.cjs +1 -0
  349. package/dist/lib/url/types.d.ts +18 -0
  350. package/dist/lib/url/types.d.ts.map +1 -0
  351. package/dist/lib/url/types.js +1 -0
  352. package/dist/lib/url/types.mjs +0 -0
  353. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  354. package/package.json +150 -0
@@ -0,0 +1,1301 @@
1
+ /**
2
+ * String utilities collection for TypeScript
3
+ * Provides optimized methods for common string operations
4
+ */
5
+ import { parseJsObjectLiteral } from './parser.js';
6
+ /**
7
+ * Trims whitespace from both ends of a string with high performance
8
+ * @param str - The string to trim
9
+ * @returns Trimmed string
10
+ * @example
11
+ * trim(" hello ") // "hello"
12
+ */
13
+ export const trim = (str) => {
14
+ // Use native trim for best performance
15
+ return str.trim();
16
+ };
17
+ /**
18
+ * Trims whitespace from the start of a string
19
+ * @param str - The string to trim
20
+ * @returns Left-trimmed string
21
+ * @example
22
+ * trimStart(" hello") // "hello"
23
+ */
24
+ export const trimStart = (str) => {
25
+ return str.trimStart();
26
+ };
27
+ /**
28
+ * Trims whitespace from the end of a string
29
+ * @param str - The string to trim
30
+ * @returns Right-trimmed string
31
+ * @example
32
+ * trimEnd("hello ") // "hello"
33
+ */
34
+ export const trimEnd = (str) => {
35
+ return str.trimEnd();
36
+ };
37
+ /**
38
+ * Converts string to camelCase
39
+ * @param str - The string to convert
40
+ * @returns camelCase string
41
+ * @example
42
+ * toCamelCase("hello-world") // "helloWorld"
43
+ */
44
+ export const toCamelCase = (str) => {
45
+ return str
46
+ .replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase())
47
+ .replace(/^[A-Z]/, (chr) => chr.toLowerCase());
48
+ };
49
+ /**
50
+ * Converts string to PascalCase
51
+ * @param str - The string to convert
52
+ * @returns PascalCase string
53
+ * @example
54
+ * toPascalCase("hello-world") // "HelloWorld"
55
+ */
56
+ export const toPascalCase = (str) => {
57
+ return str
58
+ .replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase())
59
+ .replace(/^[a-z]/, (chr) => chr.toUpperCase());
60
+ };
61
+ /**
62
+ * Converts string to kebab-case
63
+ * @param str - The string to convert
64
+ * @returns kebab-case string
65
+ * @example
66
+ * toKebabCase("helloWorld") // "hello-world"
67
+ */
68
+ export const toKebabCase = (str) => {
69
+ return str
70
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
71
+ .replace(/[_\s]+/g, '-')
72
+ .toLowerCase();
73
+ };
74
+ /**
75
+ * Converts string to snake_case
76
+ * @param str - The string to convert
77
+ * @returns snake_case string
78
+ * @example
79
+ * toSnakeCase("helloWorld") // "hello_world"
80
+ */
81
+ export const toSnakeCase = (str) => {
82
+ return str
83
+ .replace(/([a-z])([A-Z])/g, '$1_$2')
84
+ .replace(/[-\s]+/g, '_')
85
+ .toLowerCase();
86
+ };
87
+ /**
88
+ * Capitalizes the first letter of a string
89
+ * @param str - The string to capitalize
90
+ * @returns Capitalized string
91
+ * @example
92
+ * capitalize("hello") // "Hello"
93
+ */
94
+ export const capitalize = (str) => {
95
+ if (!str)
96
+ return str;
97
+ return str.charAt(0).toUpperCase() + str.slice(1);
98
+ };
99
+ /**
100
+ * Converts string to title case (each word capitalized)
101
+ * @param str - The string to convert
102
+ * @returns Title case string
103
+ * @example
104
+ * toTitleCase("hello world") // "Hello World"
105
+ */
106
+ export const toTitleCase = (str) => {
107
+ return str.replace(/\b\w+/g, (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
108
+ };
109
+ /**
110
+ * Checks if string starts with a substring (case-sensitive)
111
+ * @param str - The string to check
112
+ * @param search - The substring to search for
113
+ * @param position - Position to start searching (default: 0)
114
+ * @returns True if string starts with search string
115
+ * @example
116
+ * startsWith("hello", "he") // true
117
+ */
118
+ export const startsWith = (str, search, position = 0) => {
119
+ return str.startsWith(search, position);
120
+ };
121
+ /**
122
+ * Checks if string ends with a substring (case-sensitive)
123
+ * @param str - The string to check
124
+ * @param search - The substring to search for
125
+ * @param length - Length to use (default: str.length)
126
+ * @returns True if string ends with search string
127
+ * @example
128
+ * endsWith("hello", "lo") // true
129
+ */
130
+ export const endsWith = (str, search, length) => {
131
+ return str.endsWith(search, length);
132
+ };
133
+ /**
134
+ * Checks if string contains a substring (case-sensitive)
135
+ * @param str - The string to check
136
+ * @param search - The substring to search for
137
+ * @returns True if string contains search string
138
+ * @example
139
+ * includes("hello", "ell") // true
140
+ */
141
+ export const includes = (str, search) => {
142
+ return str.includes(search);
143
+ };
144
+ /**
145
+ * Checks if string contains a substring (case-insensitive)
146
+ * @param str - The string to check
147
+ * @param search - The substring to search for
148
+ * @returns True if string contains search string (case-insensitive)
149
+ * @example
150
+ * includesIgnoreCase("Hello", "hello") // true
151
+ */
152
+ export const includesIgnoreCase = (str, search) => {
153
+ return str.toLowerCase().includes(search.toLowerCase());
154
+ };
155
+ /**
156
+ * Replaces all occurrences of a substring (case-sensitive)
157
+ * @param str - The string to process
158
+ * @param search - The substring to replace
159
+ * @param replacement - The replacement string
160
+ * @returns String with all occurrences replaced
161
+ * @example
162
+ * replaceAll("hello world", "l", "x") // "hexxo worxd"
163
+ */
164
+ export const replaceAll = (str, search, replacement) => {
165
+ // Use native replaceAll if available, otherwise use regex with escape
166
+ if (typeof str.replaceAll === 'function') {
167
+ return str.replaceAll(search, replacement);
168
+ }
169
+ return str.replace(new RegExp(escapeRegExp(search), 'g'), replacement);
170
+ };
171
+ /**
172
+ * Replaces all occurrences of a substring (case-insensitive)
173
+ * @param str - The string to process
174
+ * @param search - The substring to replace
175
+ * @param replacement - The replacement string
176
+ * @returns String with all occurrences replaced (case-insensitive)
177
+ * @example
178
+ * replaceAllIgnoreCase("Hello World", "hello", "Hi") // "Hi World"
179
+ */
180
+ export const replaceAllIgnoreCase = (str, search, replacement) => {
181
+ return str.replace(new RegExp(escapeRegExp(search), 'gi'), replacement);
182
+ };
183
+ /**
184
+ * Escapes regex special characters in a string
185
+ * @param str - The string to escape
186
+ * @returns Escaped string safe for use in regex
187
+ * @example
188
+ * escapeRegExp(".*+?^${}()|[]\\") // "\\.\\*\\+\\?\\^\\$\\{\\}\\(\\)\\|\\[\\]\\\\"
189
+ */
190
+ export const escapeRegExp = (str) => {
191
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
192
+ };
193
+ /**
194
+ * Escapes HTML special characters
195
+ * @param str - The string to escape
196
+ * @returns HTML-escaped string
197
+ * @example
198
+ * escapeHtml("<div>") // "&lt;div&gt;"
199
+ */
200
+ export const escapeHtml = (str) => {
201
+ const htmlEntities = {
202
+ '&': '&amp;',
203
+ '<': '&lt;',
204
+ '>': '&gt;',
205
+ '"': '&quot;',
206
+ "'": '&#39;',
207
+ '/': '&#x2F;',
208
+ };
209
+ return str.replace(/[&<>"'/]/g, (char) => htmlEntities[char] || char);
210
+ };
211
+ /**
212
+ * Unescapes HTML entities
213
+ * @param str - The string to unescape
214
+ * @returns Unescaped string
215
+ * @example
216
+ * unescapeHtml("&lt;div&gt;") // "<div>"
217
+ */
218
+ export const unescapeHtml = (str) => {
219
+ const htmlEntities = {
220
+ '&amp;': '&',
221
+ '&lt;': '<',
222
+ '&gt;': '>',
223
+ '&quot;': '"',
224
+ '&#39;': "'",
225
+ '&#x2F;': '/',
226
+ };
227
+ return str.replace(/&(?:amp|lt|gt|quot|#39|#x2F);/g, (entity) => htmlEntities[entity] || entity);
228
+ };
229
+ /**
230
+ * Truncates string to specified length with ellipsis
231
+ * @param str - The string to truncate
232
+ * @param length - Maximum length
233
+ * @param ellipsis - Ellipsis string (default: "...")
234
+ * @returns Truncated string
235
+ * @example
236
+ * truncate("Hello world", 8) // "Hello..."
237
+ */
238
+ export const truncate = (str, length, ellipsis = '...') => {
239
+ if (str.length <= length)
240
+ return str;
241
+ return str.slice(0, length - ellipsis.length) + ellipsis;
242
+ };
243
+ /**
244
+ * Pads string to specified length with character
245
+ * @param str - The string to pad
246
+ * @param length - Target length
247
+ * @param padChar - Character to pad with (default: " ")
248
+ * @param side - Which side to pad: "start", "end", or "both" (default: "start")
249
+ * @returns Padded string
250
+ * @example
251
+ * pad("hello", 10, "*", "both") // "**hello***"
252
+ */
253
+ export const pad = (str, length, padChar = ' ', side = 'start') => {
254
+ const paddingNeeded = length - str.length;
255
+ if (paddingNeeded <= 0)
256
+ return str;
257
+ const padStr = padChar.repeat(paddingNeeded);
258
+ switch (side) {
259
+ case 'start':
260
+ return padStr + str;
261
+ case 'end':
262
+ return str + padStr;
263
+ case 'both':
264
+ const leftPad = Math.floor(paddingNeeded / 2);
265
+ const rightPad = paddingNeeded - leftPad;
266
+ return padChar.repeat(leftPad) + str + padChar.repeat(rightPad);
267
+ }
268
+ };
269
+ /**
270
+ * Checks if string is empty or whitespace only
271
+ * @param str - The string to check
272
+ * @returns True if string is empty or whitespace only
273
+ * @example
274
+ * isEmpty(" ") // true
275
+ * isEmpty("hello") // false
276
+ */
277
+ export const isEmpty = (str) => {
278
+ return str.trim().length === 0;
279
+ };
280
+ /**
281
+ * Checks if string is a valid email address
282
+ * @param email - The email string to validate
283
+ * @returns True if string is a valid email
284
+ * @example
285
+ * isValidEmail("test@example.com") // true
286
+ */
287
+ export const isValidEmail = (email) => {
288
+ // RFC 5322 compliant regex (simplified but effective)
289
+ const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
290
+ return emailRegex.test(email.trim());
291
+ };
292
+ /**
293
+ * Checks if string is a valid URL
294
+ * @param url - The URL string to validate
295
+ * @returns True if string is a valid URL
296
+ * @example
297
+ * isValidUrl("https://example.com") // true
298
+ */
299
+ export const isValidUrl = (url) => {
300
+ try {
301
+ new URL(url);
302
+ return true;
303
+ }
304
+ catch {
305
+ return false;
306
+ }
307
+ };
308
+ /**
309
+ * Extracts domain from URL
310
+ * @param url - The URL string
311
+ * @returns Domain name or empty string
312
+ * @example
313
+ * extractDomain("https://www.example.com/path") // "example.com"
314
+ */
315
+ export const extractDomain = (url) => {
316
+ try {
317
+ const urlObj = new URL(url);
318
+ return urlObj.hostname.replace(/^www\./, '');
319
+ }
320
+ catch {
321
+ return '';
322
+ }
323
+ };
324
+ /**
325
+ * Generates a random string of specified length
326
+ * @param length - Length of random string
327
+ * @param charset - Character set to use (default: alphanumeric)
328
+ * @returns Random string
329
+ * @example
330
+ * randomString(10) // "aB3xYz78pQ"
331
+ */
332
+ export const randomString = (length = 10, charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') => {
333
+ let result = '';
334
+ const charsetLength = charset.length;
335
+ for (let i = 0; i < length; i++) {
336
+ result += charset.charAt(Math.floor(Math.random() * charsetLength));
337
+ }
338
+ return result;
339
+ };
340
+ /**
341
+ * Counts occurrences of substring in string
342
+ * @param str - The string to search
343
+ * @param search - The substring to count
344
+ * @param caseSensitive - Whether search is case-sensitive (default: true)
345
+ * @returns Number of occurrences
346
+ * @example
347
+ * countOccurrences("hello hello", "lo") // 2
348
+ */
349
+ export const countOccurrences = (str, search, caseSensitive = true) => {
350
+ if (!search)
351
+ return 0;
352
+ const source = caseSensitive ? str : str.toLowerCase();
353
+ const target = caseSensitive ? search : search.toLowerCase();
354
+ let count = 0;
355
+ let position = 0;
356
+ while ((position = source.indexOf(target, position)) !== -1) {
357
+ count++;
358
+ position += target.length;
359
+ }
360
+ return count;
361
+ };
362
+ /**
363
+ * Removes all whitespace from string
364
+ * @param str - The string to process
365
+ * @returns String without whitespace
366
+ * @example
367
+ * removeWhitespace("hello world") // "helloworld"
368
+ */
369
+ export const removeWhitespace = (str) => {
370
+ return str.replace(/\s+/g, '');
371
+ };
372
+ /**
373
+ * Reverses a string
374
+ * @param str - The string to reverse
375
+ * @returns Reversed string
376
+ * @example
377
+ * reverse("hello") // "olleh"
378
+ */
379
+ export const reverse = (str) => {
380
+ return str.split('').reverse().join('');
381
+ };
382
+ /**
383
+ * Checks if string is palindrome (reads same forwards and backwards)
384
+ * @param str - The string to check
385
+ * @param caseSensitive - Whether comparison is case-sensitive (default: false)
386
+ * @returns True if string is palindrome
387
+ * @example
388
+ * isPalindrome("racecar") // true
389
+ */
390
+ export const isPalindrome = (str, caseSensitive = false) => {
391
+ const normalized = caseSensitive ? str : str.toLowerCase();
392
+ const cleaned = normalized.replace(/[^a-z0-9]/gi, '');
393
+ return cleaned === reverse(cleaned);
394
+ };
395
+ /**
396
+ * Generates slug from string (URL-friendly)
397
+ * @param str - The string to convert
398
+ * @returns URL-friendly slug
399
+ * @example
400
+ * slugify("Hello World!") // "hello-world"
401
+ */
402
+ export const slugify = (str) => {
403
+ return str
404
+ .toLowerCase()
405
+ .trim()
406
+ .replace(/[^\w\s-]/g, '')
407
+ .replace(/[\s_-]+/g, '-')
408
+ .replace(/^-+|-+$/g, '');
409
+ };
410
+ /**
411
+ * Masks part of a string (e.g., for hiding sensitive data)
412
+ * @param str - The string to mask
413
+ * @param visibleStart - Number of characters to keep at start
414
+ * @param visibleEnd - Number of characters to keep at end
415
+ * @param maskChar - Character to use for masking (default: "*")
416
+ * @returns Masked string
417
+ * @example
418
+ * mask("1234567890", 3, 2) // "123*****90"
419
+ */
420
+ export const mask = (str, visibleStart = 0, visibleEnd = 0, maskChar = '*') => {
421
+ if (visibleStart + visibleEnd >= str.length) {
422
+ return str;
423
+ }
424
+ const start = str.slice(0, visibleStart);
425
+ const end = visibleEnd > 0 ? str.slice(-visibleEnd) : '';
426
+ const middle = maskChar.repeat(str.length - visibleStart - visibleEnd);
427
+ return start + middle + end;
428
+ };
429
+ /**
430
+ * Generates initials from name
431
+ * @param name - The full name
432
+ * @param maxInitials - Maximum number of initials (default: 2)
433
+ * @returns Initials string
434
+ * @example
435
+ * getInitials("John Doe") // "JD"
436
+ */
437
+ export const getInitials = (name, maxInitials = 2) => {
438
+ return name
439
+ .split(/\s+/)
440
+ .slice(0, maxInitials)
441
+ .map((word) => word.charAt(0).toUpperCase())
442
+ .join('');
443
+ };
444
+ /**
445
+ * Normalizes line endings to LF (Unix-style)
446
+ * @param str - The string to normalize
447
+ * @returns String with normalized line endings
448
+ * @example
449
+ * normalizeLineEndings("hello\r\nworld") // "hello\nworld"
450
+ */
451
+ export const normalizeLineEndings = (str) => {
452
+ return str.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
453
+ };
454
+ /**
455
+ * Wraps text to specified line length
456
+ * @param text - The text to wrap
457
+ * @param lineLength - Maximum line length
458
+ * @returns Array of wrapped lines
459
+ * @example
460
+ * wordWrap("Hello world, this is a test.", 10)
461
+ * // ["Hello", "world, this", "is a test."]
462
+ */
463
+ export const wordWrap = (text, lineLength = 80) => {
464
+ const words = text.split(' ');
465
+ const lines = [];
466
+ let currentLine = '';
467
+ for (const word of words) {
468
+ const len = currentLine.length + word.length + 1;
469
+ if (currentLine.length + word.length <= lineLength) {
470
+ currentLine += (currentLine ? ' ' : '') + word;
471
+ }
472
+ else {
473
+ if (currentLine) {
474
+ lines.push(currentLine);
475
+ }
476
+ currentLine = word;
477
+ }
478
+ }
479
+ if (currentLine) {
480
+ lines.push(currentLine);
481
+ }
482
+ return lines;
483
+ };
484
+ /**
485
+ * Type guard for string values
486
+ * @param value - Value to check
487
+ * @returns True if value is a string
488
+ */
489
+ export const isString = (value) => {
490
+ return typeof value === 'string';
491
+ };
492
+ /**
493
+ * Safely converts any value to string
494
+ * @param value - Value to convert
495
+ * @param fallback - Fallback value if conversion fails (default: "")
496
+ * @returns String representation or fallback
497
+ */
498
+ export const toString = (value, fallback) => {
499
+ if (value == null) {
500
+ return fallback !== undefined ? fallback : '';
501
+ }
502
+ const v = value;
503
+ if (Array.isArray(v)) {
504
+ if (v.length === 0) {
505
+ return fallback !== undefined ? fallback : '';
506
+ }
507
+ }
508
+ else {
509
+ if (typeof v === 'object' && Object.keys(v).length === 0) {
510
+ return fallback !== undefined ? fallback : '';
511
+ }
512
+ }
513
+ if (typeof value === 'string') {
514
+ return value;
515
+ }
516
+ if (typeof value === 'number' || typeof value === 'boolean') {
517
+ return String(value);
518
+ }
519
+ try {
520
+ return String(value);
521
+ }
522
+ catch {
523
+ return fallback !== undefined ? fallback : '';
524
+ }
525
+ };
526
+ /**
527
+ * Escapes regex special characters in a string
528
+ * @param str - The string to escape
529
+ * @param escape - Whether to escape the string (default: true)
530
+ * @returns Escaped string or original if escape is false or string is in exclude list
531
+ * @example
532
+ * escapeString("test[123]") // "test\\[123\\]"
533
+ * escapeString("&nbsp;", true) // "&nbsp;" (not escaped due to exclude list)
534
+ */
535
+ export const escapeString = (str, escape = true) => {
536
+ // Fast path: return early if escaping is disabled
537
+ if (!escape) {
538
+ return str;
539
+ }
540
+ // Use a Set for O(1) lookup instead of O(n) array search
541
+ const exclude = new Set(['&nbsp;', '\xa0', '\xa0\xa0', '_space_']);
542
+ // Check if string should be excluded from escaping
543
+ if (exclude.has(str)) {
544
+ return str;
545
+ }
546
+ // Optimized regex: escape only regex special characters
547
+ // Note: Only characters that have special meaning in regex need escaping
548
+ const regexSpecialChars = /[.*+?^${}()|[\]\\]/g;
549
+ // Use replace with a function to handle the replacement
550
+ return str.replace(regexSpecialChars, '\\$&');
551
+ };
552
+ /**
553
+ * Replaces a substring by index position
554
+ * @param {string} original - Original string
555
+ * @param {number} startIndex - Start index (inclusive)
556
+ * @param {number} endIndex - End index (exclusive)
557
+ * @param {string} replacement - Replacement string
558
+ * @returns {string} Modified string
559
+ */
560
+ function replaceStringByIndex(original, startIndex, endIndex, replacement) {
561
+ if (startIndex < 0 || startIndex > original.length) {
562
+ throw new Error('Start index out of bounds');
563
+ }
564
+ if (endIndex < startIndex || endIndex > original.length) {
565
+ throw new Error('End index out of bounds');
566
+ }
567
+ const before = original.substring(0, startIndex);
568
+ const after = original.substring(endIndex);
569
+ return before + replacement + after;
570
+ }
571
+ /**
572
+ * Replaces a substring at the beginning or end of a string
573
+ * @param originalString - The original string to modify
574
+ * @param valueToReplace - The substring to replace
575
+ * @param position - Position to replace: "start", "end", or "both" (default: "start")
576
+ * @param newValue - The replacement value (default: "")
577
+ * @returns Modified string or original if replacement not applicable
578
+ * @example
579
+ * replaceString("hello world", "hello", "start") // " world"
580
+ * replaceString("hello world", "world", "end") // "hello "
581
+ * replaceString("test.test", ".", "both", "-") // "test-test"
582
+ */
583
+ export const replaceString = (originalString, valueToReplace, position = 'start', newValue = '') => {
584
+ // Validate inputs
585
+ if (!originalString ||
586
+ !valueToReplace ||
587
+ valueToReplace.length === 0 ||
588
+ originalString.length < valueToReplace.length) {
589
+ return originalString;
590
+ }
591
+ // Handle both positions case
592
+ if (position === 'both') {
593
+ let result = originalString;
594
+ // Replace from start if applicable
595
+ if (result.startsWith(valueToReplace)) {
596
+ result = replaceStringByIndex(result, 0, valueToReplace.length, newValue);
597
+ // result = result.substring(valueToReplace.length);
598
+ }
599
+ // Replace from end if applicable
600
+ if (result.endsWith(valueToReplace)) {
601
+ result = replaceStringByIndex(result, result.length - valueToReplace.length, result.length, newValue);
602
+ // result = result.substring(0, result.length - valueToReplace.length);
603
+ }
604
+ // return result.length < originalString.length
605
+ // ? newValue + result + newValue
606
+ // : result;
607
+ return result;
608
+ }
609
+ // Handle start or end position
610
+ const shouldReplace = (position === 'start' && originalString.startsWith(valueToReplace)) ||
611
+ (position === 'end' && originalString.endsWith(valueToReplace));
612
+ if (!shouldReplace) {
613
+ return originalString;
614
+ }
615
+ if (position === 'start') {
616
+ return newValue + originalString.substring(valueToReplace.length);
617
+ }
618
+ else {
619
+ return (originalString.substring(0, originalString.length - valueToReplace.length) + newValue);
620
+ }
621
+ };
622
+ /**
623
+ * Alternative version with regex for more complex patterns
624
+ * Replaces a pattern at start/end using regex for more control
625
+ * @param originalString - The original string to modify
626
+ * @param pattern - Regex pattern or string to match
627
+ * @param position - Position to replace: "start", "end", or "both"
628
+ * @param newValue - The replacement value
629
+ * @param useRegex - Whether pattern is a regex pattern
630
+ * @returns Modified string
631
+ */
632
+ export const replaceStringPattern = (originalString, options) => {
633
+ let { pattern, position, newValue, useRegex = false, flags } = { ...options };
634
+ if (!originalString) {
635
+ return originalString;
636
+ }
637
+ if (!newValue) {
638
+ newValue = '';
639
+ }
640
+ let regex;
641
+ const isStart = typeof position === 'undefined' || position === 'start';
642
+ if (useRegex && pattern instanceof RegExp) {
643
+ regex = pattern;
644
+ const regex_string = regex.source;
645
+ if (position) {
646
+ if (position === 'start') {
647
+ pattern = `^${regex_string}`;
648
+ }
649
+ else if (position === 'end') {
650
+ pattern = `${regex_string}$`;
651
+ }
652
+ else {
653
+ pattern = `^${regex_string}|${regex_string}$`;
654
+ }
655
+ pattern = new RegExp(pattern, flags);
656
+ }
657
+ }
658
+ else if (useRegex) {
659
+ if (position) {
660
+ if (position === 'start') {
661
+ pattern = `^${pattern}`;
662
+ }
663
+ else if (position === 'end') {
664
+ pattern = `${pattern}$`;
665
+ }
666
+ else if (position === 'both') {
667
+ pattern = `^${pattern}|${pattern}$`;
668
+ }
669
+ }
670
+ regex = new RegExp(pattern, flags);
671
+ }
672
+ else {
673
+ const escapedPattern = pattern;
674
+ regex = new RegExp(isStart
675
+ ? `^${escapedPattern}`
676
+ : position === 'end'
677
+ ? `${escapedPattern}$`
678
+ : position === 'both'
679
+ ? `^${escapedPattern}|${escapedPattern}$`
680
+ : `${escapedPattern}`, flags || 'g');
681
+ }
682
+ return originalString.replace(regex, newValue);
683
+ };
684
+ /**
685
+ * Type for the parsed object in stringToObjectArray
686
+ */
687
+ // type ParsedObject = Record<string, any> | string | number | boolean | null;
688
+ // /**
689
+ // * Parses a string or string array into an array of objects or strings
690
+ // * Supports JSON, delimited strings, and various formats
691
+ // * @param input - The input string or array to parse
692
+ // * @param options - Configuration options for parsing
693
+ // * @returns Array of parsed objects or strings
694
+ // * @example
695
+ // * // Returns: [{value: "apple", label: "apple"}, {value: "banana", label: "banana"}]
696
+ // * stringToObjectArray("apple|banana", {valueKey: "value", labelKey: "label"})
697
+ // *
698
+ // * // Returns: ["apple", "banana"]
699
+ // * stringToObjectArray("apple,banana", {delimiters: [","]})
700
+ // *
701
+ // * // Returns: parsed JSON array
702
+ // * stringToObjectArray('[{"id": 1, "name": "test"}]')
703
+ // */
704
+ // export const stringToObjectArray = (
705
+ // input: string | string[] | any[],
706
+ // options: StringToObjectArrayOptions = {}
707
+ // ): ParsedObject[] => {
708
+ // const {
709
+ // delimiters = ['|'],
710
+ // valueKey = 'value',
711
+ // labelKey = 'label',
712
+ // defaultObject = {},
713
+ // trimItems = true,
714
+ // filterEmpty = true,
715
+ // } = options;
716
+ // // Helper function to create object from string
717
+ // const createObject = (item: string): Record<string, any> => {
718
+ // const base = { ...defaultObject };
719
+ // const trimmed = trimItems ? item.trim() : item;
720
+ // // Only add value/label if they don't already exist in defaultObject
721
+ // if (!(valueKey in base)) {
722
+ // base[valueKey] = trimmed;
723
+ // }
724
+ // if (!(labelKey in base) && labelKey !== valueKey) {
725
+ // base[labelKey] = trimmed;
726
+ // }
727
+ // return base;
728
+ // };
729
+ // // Handle array input
730
+ // if (Array.isArray(input)) {
731
+ // return input
732
+ // .map((item): ParsedObject | null => {
733
+ // if (item == null) return null;
734
+ // if (typeof item === 'string') {
735
+ // return valueKey ? createObject(item) : item;
736
+ // }
737
+ // if (typeof item === 'object') {
738
+ // return item;
739
+ // }
740
+ // // Convert other types to string
741
+ // return valueKey ? createObject(String(item)) : String(item);
742
+ // })
743
+ // .filter((item): item is ParsedObject => {
744
+ // if (item == null) return false;
745
+ // if (filterEmpty && typeof item === 'string' && item.trim() === '')
746
+ // return false;
747
+ // if (
748
+ // filterEmpty &&
749
+ // typeof item === 'object' &&
750
+ // valueKey in item &&
751
+ // item[valueKey]?.trim() === ''
752
+ // )
753
+ // return false;
754
+ // return true;
755
+ // });
756
+ // }
757
+ // // Handle string input
758
+ // if (typeof input !== 'string') {
759
+ // return [];
760
+ // }
761
+ // const str = input.trim();
762
+ // // Return empty array for empty string
763
+ // if (str === '') {
764
+ // return [];
765
+ // }
766
+ // // Try to parse as JSON first
767
+ // if (
768
+ // (str.startsWith('[') && str.endsWith(']')) ||
769
+ // (str.startsWith('{') && str.endsWith('}'))
770
+ // ) {
771
+ // try {
772
+ // const parsed = JSON.parse(str);
773
+ // if (Array.isArray(parsed)) {
774
+ // return parsed.map((item): ParsedObject => {
775
+ // if (typeof item === 'string' && valueKey) {
776
+ // return createObject(item);
777
+ // }
778
+ // if (typeof item === 'object' && item !== null) {
779
+ // return { ...defaultObject, ...item };
780
+ // }
781
+ // return valueKey ? createObject(String(item)) : String(item);
782
+ // });
783
+ // }
784
+ // // Single object
785
+ // return [{ ...defaultObject, ...parsed }];
786
+ // } catch {
787
+ // // Not valid JSON, continue with other methods
788
+ // }
789
+ // }
790
+ // // Try to parse as array literal (handles cases like "[a, b, c]")
791
+ // const literalResult = parseArrayLiteral(str);
792
+ // if (Array.isArray(literalResult)) {
793
+ // return literalResult.map((item) =>
794
+ // valueKey ? createObject(String(item)) : String(item)
795
+ // );
796
+ // }
797
+ // // Try each delimiter
798
+ // for (const delimiter of delimiters) {
799
+ // if (str.includes(delimiter)) {
800
+ // const parts = str.split(delimiter);
801
+ // const items = trimItems ? parts.map((part) => part.trim()) : parts;
802
+ // return items
803
+ // .filter((item) => !filterEmpty || item !== '')
804
+ // .map((item) => (valueKey ? createObject(item) : item));
805
+ // }
806
+ // }
807
+ // // Single value
808
+ // return valueKey ? [createObject(str)] : [str];
809
+ // };
810
+ /**
811
+ * Parses a string representation of an array literal
812
+ * Supports formats like: [a, b, c], ["a", "b"], ['a', 'b']
813
+ * @param str - The string to parse
814
+ * @returns Array of strings if successful, original string otherwise
815
+ * @example
816
+ * parseArrayLiteral("[apple, banana, cherry]") // ["apple", "banana", "cherry"]
817
+ * parseArrayLiteral('["apple", "banana"]') // ["apple", "banana"]
818
+ */
819
+ export const parseArrayLiteral = (str) => {
820
+ // Early return if not an array literal
821
+ if (!str.startsWith('[') || !str.endsWith(']')) {
822
+ return str;
823
+ }
824
+ const innerStr = str.slice(1, -1).trim();
825
+ // Handle empty array
826
+ if (innerStr === '') {
827
+ return [];
828
+ }
829
+ // Try JSON parse first for quoted strings
830
+ try {
831
+ // Wrap in brackets and parse as JSON
832
+ const jsonStr = `[${innerStr}]`;
833
+ const parsed = JSON.parse(jsonStr);
834
+ if (Array.isArray(parsed)) {
835
+ // return parsed.map(String);
836
+ return parsed;
837
+ }
838
+ }
839
+ catch {
840
+ // Not valid JSON, continue with manual parsing
841
+ }
842
+ // Manual parsing for unquoted strings
843
+ const items = [];
844
+ let current = '';
845
+ let inQuotes = false;
846
+ let quoteChar = '';
847
+ let escaped = false;
848
+ let depth = 0; // Handle nested brackets
849
+ for (let i = 0; i < innerStr.length; i++) {
850
+ const char = innerStr[i];
851
+ // Handle escaping
852
+ if (escaped) {
853
+ current += char;
854
+ escaped = false;
855
+ continue;
856
+ }
857
+ // Check for escape character
858
+ if (char === '\\' && inQuotes) {
859
+ escaped = true;
860
+ continue;
861
+ }
862
+ // Handle quotes
863
+ if ((char === '"' || char === "'") && !inQuotes) {
864
+ inQuotes = true;
865
+ quoteChar = char;
866
+ }
867
+ else if (char === quoteChar && inQuotes) {
868
+ inQuotes = false;
869
+ quoteChar = '';
870
+ }
871
+ // Handle nested brackets
872
+ else if (char === '[' && !inQuotes) {
873
+ depth++;
874
+ current += char;
875
+ }
876
+ else if (char === ']' && !inQuotes) {
877
+ depth--;
878
+ current += char;
879
+ }
880
+ // Handle comma as delimiter (only when not in quotes and not in nested brackets)
881
+ else if (char === ',' && !inQuotes && depth === 0) {
882
+ items.push(current.trim());
883
+ current = '';
884
+ }
885
+ else {
886
+ current += char;
887
+ }
888
+ }
889
+ // Add the last item
890
+ if (current.trim()) {
891
+ items.push(current.trim());
892
+ }
893
+ // Clean up items: remove surrounding quotes
894
+ return items.map((item) => {
895
+ const trimmed = item.trim();
896
+ // Remove surrounding quotes if present
897
+ if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
898
+ (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
899
+ return trimmed.slice(1, -1);
900
+ }
901
+ return trimmed;
902
+ });
903
+ };
904
+ /**
905
+ * Enhanced version that handles both array literals and object literals
906
+ * @param str - The string to parse
907
+ * @returns Parsed array, object, or original string
908
+ */
909
+ export const parseLiteral = (str) => {
910
+ const trimmed = str.trim();
911
+ // Try to parse as array literal
912
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
913
+ const result = parseArrayLiteral(trimmed);
914
+ return Array.isArray(result) ? result : trimmed;
915
+ }
916
+ // Try to parse as object literal
917
+ if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
918
+ try {
919
+ return JSON.parse(trimmed);
920
+ }
921
+ catch {
922
+ // Try to fix common issues
923
+ const p = parseJsObjectLiteral(trimmed);
924
+ if (p !== undefined) {
925
+ return p;
926
+ }
927
+ const fixed = trimmed
928
+ .replace(/([{,]\s*)(\w+)(\s*:)/g, '$1"$2"$3') // Add quotes to unquoted keys
929
+ .replace(/:\s*'([^']*)'/g, ':"$1"'); // Convert single quotes to double quotes
930
+ try {
931
+ return JSON.parse(fixed);
932
+ }
933
+ catch {
934
+ return trimmed;
935
+ }
936
+ }
937
+ }
938
+ // Try to parse as JSON (might be a number, boolean, or null)
939
+ try {
940
+ return JSON.parse(trimmed);
941
+ }
942
+ catch {
943
+ return trimmed;
944
+ }
945
+ };
946
+ /**
947
+ * Type guard to check if a value is a string array
948
+ * @param value - Value to check
949
+ * @returns True if value is a string array
950
+ */
951
+ export const isStringArray = (value) => {
952
+ return (Array.isArray(value) && value.every((item) => typeof item === 'string'));
953
+ };
954
+ /**
955
+ * Parses a string or string array into an array of objects or primitive values
956
+ * Supports JSON, delimited strings, and various formats
957
+ * @param input - The input string or array to parse
958
+ * @param options - Configuration options for parsing
959
+ * @returns Array of parsed objects or primitive values
960
+ * @example
961
+ * // Returns primitive array: ["apple", "banana"]
962
+ * stringToObjectArray("apple|banana")
963
+ *
964
+ * // Returns object array: [{value: "apple", label: "apple"}, {value: "banana", label: "banana"}]
965
+ * stringToObjectArray("apple|banana", {valueKey: "value", labelKey: "label"})
966
+ *
967
+ * // Returns object array with defaults: [{id: "apple", name: "apple", type: "fruit"}, ...]
968
+ * stringToObjectArray("apple|banana", {valueKey: "id", labelKey: "name", defaultObject: {type: "fruit"}})
969
+ *
970
+ * // Returns parsed primitives: [1, 2, 3]
971
+ * stringToObjectArray("1|2|3", {parsePrimitives: true})
972
+ */
973
+ export const stringToObjectArray = (input, options = {}) => {
974
+ const { delimiters = ['|'], valueKey, labelKey, defaultObject, trimItems = true, filterEmpty = true, returnObjects, parsePrimitives = false, preserveNullUndefined = false, } = options;
975
+ // Auto-detect if we should return objects
976
+ // Return objects if: returnObjects is true OR valueKey/labelKey/defaultObject is provided
977
+ const shouldReturnObjects = returnObjects ??
978
+ (valueKey !== undefined ||
979
+ labelKey !== undefined ||
980
+ defaultObject !== undefined);
981
+ // Helper function to create object from string
982
+ const createObject = (item) => {
983
+ const base = defaultObject ? { ...defaultObject } : {};
984
+ const trimmed = trimItems ? item.trim() : item;
985
+ // Only add value if valueKey is provided
986
+ if (valueKey !== undefined) {
987
+ base[valueKey] = parsePrimitives ? parsePrimitiveValue(trimmed) : trimmed;
988
+ }
989
+ if (valueKey !== labelKey ||
990
+ (valueKey === undefined && labelKey === undefined)) {
991
+ // Only add label if labelKey is provided and different from valueKey
992
+ let label;
993
+ if (valueKey === undefined && labelKey === undefined) {
994
+ label = returnObjects ? 'label' : valueKey;
995
+ }
996
+ else {
997
+ label = labelKey;
998
+ }
999
+ if (label !== undefined) {
1000
+ base[label] = trimmed;
1001
+ }
1002
+ }
1003
+ return base;
1004
+ };
1005
+ // Helper function to parse primitive value
1006
+ const parsePrimitiveValue = (str) => {
1007
+ const trimmed = str.trim();
1008
+ if (trimmed === '') {
1009
+ return preserveNullUndefined ? null : '';
1010
+ }
1011
+ // Parse null
1012
+ if (trimmed.toLowerCase() === 'null') {
1013
+ return preserveNullUndefined ? null : 'null';
1014
+ }
1015
+ // Parse undefined
1016
+ if (trimmed.toLowerCase() === 'undefined') {
1017
+ return preserveNullUndefined ? null : 'undefined';
1018
+ }
1019
+ // Parse boolean
1020
+ if (trimmed.toLowerCase() === 'true')
1021
+ return true;
1022
+ if (trimmed.toLowerCase() === 'false')
1023
+ return false;
1024
+ // Parse number (integers and floats)
1025
+ if (/^-?\d+$/.test(trimmed)) {
1026
+ const num = parseInt(trimmed, 10);
1027
+ return isNaN(num) ? (trimItems ? trimmed : str) : num;
1028
+ }
1029
+ if (/^-?\d+\.\d+$/.test(trimmed)) {
1030
+ const num = parseFloat(trimmed);
1031
+ return isNaN(num) ? (trimItems ? trimmed : str) : num;
1032
+ }
1033
+ if (!trimItems)
1034
+ return str;
1035
+ // Return string as-is
1036
+ return trimmed;
1037
+ };
1038
+ // Helper function to process a single item
1039
+ const processItem = (item) => {
1040
+ // Handle null/undefined
1041
+ if (item == null) {
1042
+ return preserveNullUndefined ? item : null;
1043
+ }
1044
+ // Process string items
1045
+ if (typeof item === 'string') {
1046
+ const processed = trimItems ? item.trim() : item;
1047
+ if (item === 'null')
1048
+ return (preserveNullUndefined ? null : null);
1049
+ if (item === 'undefined')
1050
+ return (preserveNullUndefined ? undefined : 'undefined');
1051
+ if (item === '')
1052
+ return (preserveNullUndefined ? null : '');
1053
+ // Filter empty strings if needed
1054
+ if (filterEmpty && processed === '') {
1055
+ return preserveNullUndefined ? processed : null;
1056
+ }
1057
+ if (shouldReturnObjects) {
1058
+ return createObject(processed);
1059
+ }
1060
+ else {
1061
+ return (parsePrimitives ? parsePrimitiveValue(processed) : processed);
1062
+ }
1063
+ }
1064
+ // Process number/boolean
1065
+ if (typeof item === 'number' || typeof item === 'boolean') {
1066
+ if (shouldReturnObjects) {
1067
+ const base = defaultObject ? { ...defaultObject } : {};
1068
+ if (valueKey !== undefined)
1069
+ base[valueKey] = item;
1070
+ if (labelKey !== undefined && labelKey !== valueKey)
1071
+ base[labelKey] = String(item);
1072
+ return base;
1073
+ }
1074
+ else {
1075
+ return item;
1076
+ }
1077
+ }
1078
+ // Process existing objects
1079
+ if (typeof item === 'object' && !Array.isArray(item)) {
1080
+ if (shouldReturnObjects) {
1081
+ // Merge with defaultObject if provided
1082
+ return defaultObject
1083
+ ? { ...defaultObject, ...item }
1084
+ : item;
1085
+ }
1086
+ else {
1087
+ // Try to extract value from object
1088
+ if (valueKey && item[valueKey] !== undefined) {
1089
+ return item[valueKey];
1090
+ }
1091
+ // Fallback to string representation
1092
+ return item;
1093
+ }
1094
+ }
1095
+ // Process arrays (convert to string)
1096
+ if (Array.isArray(item)) {
1097
+ const str = JSON.stringify(item);
1098
+ if (shouldReturnObjects) {
1099
+ return createObject(str);
1100
+ }
1101
+ else {
1102
+ return str;
1103
+ }
1104
+ }
1105
+ // Default: convert to string
1106
+ const str = String(item);
1107
+ if (shouldReturnObjects) {
1108
+ return createObject(str);
1109
+ }
1110
+ else {
1111
+ return str;
1112
+ }
1113
+ };
1114
+ // Handle array input
1115
+ if (Array.isArray(input)) {
1116
+ const result = input.map(processItem);
1117
+ if (preserveNullUndefined) {
1118
+ return result;
1119
+ }
1120
+ return result.filter((item) => item !== null);
1121
+ }
1122
+ // Handle string input
1123
+ if (typeof input !== 'string') {
1124
+ // Try to convert to string
1125
+ if (input == null)
1126
+ return [];
1127
+ return processItem(String(input))
1128
+ ? [processItem(String(input))]
1129
+ : [];
1130
+ }
1131
+ const str = input.trim();
1132
+ // Return empty array for empty string
1133
+ if (str === '') {
1134
+ return [];
1135
+ }
1136
+ // Try to parse as JSON first
1137
+ if ((str.startsWith('[') && str.endsWith(']')) ||
1138
+ (str.startsWith('{') && str.endsWith('}'))) {
1139
+ try {
1140
+ const parsed = JSON.parse(str);
1141
+ if (Array.isArray(parsed)) {
1142
+ const result = parsed.map(processItem);
1143
+ if (preserveNullUndefined) {
1144
+ return result;
1145
+ }
1146
+ return result.filter((item) => item !== null);
1147
+ }
1148
+ // Single object or value
1149
+ const processed = processItem(parsed);
1150
+ return processed ? [processed] : [];
1151
+ }
1152
+ catch {
1153
+ // Not valid JSON, continue with other methods
1154
+ }
1155
+ }
1156
+ // Try to parse as array literal (handles cases like "[a, b, c]")
1157
+ const literalResult = parseArrayLiteral(str);
1158
+ if (Array.isArray(literalResult)) {
1159
+ const result = literalResult.map((item) => {
1160
+ const processed = processItem(item);
1161
+ return processed;
1162
+ });
1163
+ if (preserveNullUndefined) {
1164
+ return result;
1165
+ }
1166
+ return result.filter((item) => item !== null);
1167
+ }
1168
+ // Try each delimiter
1169
+ for (const delimiter of delimiters) {
1170
+ if (str.includes(delimiter)) {
1171
+ const parts = (trimItems ? str : input).split(delimiter);
1172
+ const result = parts.map((part) => processItem(part));
1173
+ if (preserveNullUndefined) {
1174
+ return result;
1175
+ }
1176
+ return result.filter((item) => item !== null && (!filterEmpty || item !== ''));
1177
+ }
1178
+ }
1179
+ // Single value
1180
+ const processed = processItem(str);
1181
+ return processed ? [processed] : [];
1182
+ };
1183
+ /**
1184
+ * Simplified version that always returns primitive values
1185
+ * @param input - The input string or array to parse
1186
+ * @param options - Configuration options (delimiters, trim, etc.)
1187
+ * @returns Array of primitive values
1188
+ * @example
1189
+ * stringToPrimitiveArray("apple|banana") // ["apple", "banana"]
1190
+ * stringToPrimitiveArray("1,2,3", {delimiters: [","], parsePrimitives: true}) // [1, 2, 3]
1191
+ */
1192
+ export const stringToPrimitiveArray = (input, options = {}) => {
1193
+ return stringToObjectArray(input, {
1194
+ ...options,
1195
+ returnObjects: false,
1196
+ });
1197
+ };
1198
+ /**
1199
+ * Simplified version that always returns objects
1200
+ * @param input - The input string or array to parse
1201
+ * @param options - Configuration options including valueKey, labelKey, etc.
1202
+ * @returns Array of objects
1203
+ * @example
1204
+ * stringToObjectArray("apple|banana", {valueKey: "id"}) // [{id: "apple"}, {id: "banana"}]
1205
+ */
1206
+ export const stringToObjectArrayOnly = (input, options = {}) => {
1207
+ return stringToObjectArray(input, {
1208
+ ...options,
1209
+ returnObjects: true,
1210
+ });
1211
+ };
1212
+ /**
1213
+ * Type guard to check if parsed result is primitive array
1214
+ */
1215
+ export const isPrimitiveArray = (arr) => {
1216
+ return arr.every((item) => item == null ||
1217
+ typeof item === 'string' ||
1218
+ typeof item === 'number' ||
1219
+ typeof item === 'boolean');
1220
+ };
1221
+ // Helper function used internally
1222
+ export const parsePrimitiveValue = (str) => {
1223
+ const trimmed = str.trim();
1224
+ if (trimmed === '')
1225
+ return null;
1226
+ if (trimmed.toLowerCase() === 'null')
1227
+ return null;
1228
+ if (trimmed.toLowerCase() === 'undefined')
1229
+ return undefined;
1230
+ if (trimmed.toLowerCase() === 'true')
1231
+ return true;
1232
+ if (trimmed.toLowerCase() === 'false')
1233
+ return false;
1234
+ // Try integer
1235
+ if (/^-?\d+$/.test(trimmed)) {
1236
+ const num = parseInt(trimmed, 10);
1237
+ return isNaN(num) ? trimmed : num;
1238
+ }
1239
+ // Try float
1240
+ if (/^-?\d+\.\d+$/.test(trimmed)) {
1241
+ const num = parseFloat(trimmed);
1242
+ return isNaN(num) ? trimmed : num;
1243
+ }
1244
+ // Try scientific notation
1245
+ if (/^-?\d+(?:\.\d+)?[eE][+-]?\d+$/.test(trimmed)) {
1246
+ const num = parseFloat(trimmed);
1247
+ return isNaN(num) ? trimmed : num;
1248
+ }
1249
+ return trimmed;
1250
+ };
1251
+ // Export all utilities
1252
+ export default {
1253
+ trim,
1254
+ trimStart,
1255
+ trimEnd,
1256
+ toCamelCase,
1257
+ toPascalCase,
1258
+ toKebabCase,
1259
+ toSnakeCase,
1260
+ capitalize,
1261
+ toTitleCase,
1262
+ startsWith,
1263
+ endsWith,
1264
+ includes,
1265
+ includesIgnoreCase,
1266
+ replaceStringByIndex,
1267
+ replaceAll,
1268
+ replaceAllIgnoreCase,
1269
+ escapeRegExp,
1270
+ escapeHtml,
1271
+ unescapeHtml,
1272
+ truncate,
1273
+ pad,
1274
+ isEmpty,
1275
+ isValidEmail,
1276
+ isValidUrl,
1277
+ extractDomain,
1278
+ randomString,
1279
+ countOccurrences,
1280
+ removeWhitespace,
1281
+ reverse,
1282
+ isPalindrome,
1283
+ slugify,
1284
+ mask,
1285
+ getInitials,
1286
+ normalizeLineEndings,
1287
+ wordWrap,
1288
+ isString,
1289
+ toString,
1290
+ escapeString,
1291
+ replaceString,
1292
+ replaceStringPattern,
1293
+ stringToObjectArray,
1294
+ parseArrayLiteral,
1295
+ parseLiteral,
1296
+ isStringArray,
1297
+ stringToPrimitiveArray,
1298
+ stringToObjectArrayOnly,
1299
+ isPrimitiveArray,
1300
+ parsePrimitiveValue,
1301
+ };