@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,98 @@
1
+ import "./chunk-NSBPE2FW.js";
2
+
3
+ // src/validators.ts
4
+ function isValidFilePath(filePath) {
5
+ if (!filePath || typeof filePath !== "string") return false;
6
+ if (typeof filePath === "object") return false;
7
+ if (filePath.length === 0 || filePath.length > 1e3) return false;
8
+ if (filePath.includes("../") || filePath.includes("..\\")) return false;
9
+ const suspiciousPatterns = ["//", "\\\\", "//\\", "\\//", "/./", "\\.\\"];
10
+ if (suspiciousPatterns.some((pattern) => filePath.includes(pattern))) return false;
11
+ const encodedPatterns = [
12
+ "%2e%2e%2f",
13
+ // ../
14
+ "%2e%2e/",
15
+ // ../
16
+ "%2e%2e%5c",
17
+ // ..\
18
+ "%252e"
19
+ // double-encoded
20
+ ];
21
+ if (encodedPatterns.some((pattern) => filePath.toLowerCase().includes(pattern))) return false;
22
+ if (filePath.includes("\0")) return false;
23
+ const commandChars = [";", "&", "|", "`", "$", "(", ")", "{", "}"];
24
+ if (commandChars.some((char) => filePath.includes(char))) return false;
25
+ const sqlPatterns = ["'", '"', "--", "/*", "*/", "DROP", "DELETE", "UNION", "SELECT"];
26
+ const lowerPath = filePath.toLowerCase();
27
+ if (sqlPatterns.some(
28
+ (pattern) => lowerPath.includes(pattern.toLowerCase()) && (pattern === "'" || pattern === '"' || lowerPath.includes(` ${pattern.toLowerCase()}`))
29
+ ))
30
+ return false;
31
+ const dangerousUnicode = [
32
+ "\u202E",
33
+ // Right-to-left override
34
+ "\u200B",
35
+ // Zero-width space
36
+ "\u200C",
37
+ // Zero-width non-joiner
38
+ "\u200D",
39
+ // Zero-width joiner
40
+ "\uFEFF"
41
+ // Zero-width no-break space
42
+ ];
43
+ if (dangerousUnicode.some((char) => filePath.includes(char))) return false;
44
+ if (/^[A-Za-z]:\\.*\\\.\./.test(filePath)) return false;
45
+ return true;
46
+ }
47
+ function isValidFileSize(size, maxSize) {
48
+ return typeof size === "number" && size >= 0 && size <= maxSize;
49
+ }
50
+ function isValidTextContent(content, options = {}) {
51
+ const { maxLength = 1e6 } = options;
52
+ if (typeof content !== "string") return false;
53
+ if (content.length > maxLength) return false;
54
+ const lowerContent = content.toLowerCase();
55
+ const scriptPatterns = ["<script", "<\/script", "<scr<script>ipt", "<scr\0ipt"];
56
+ if (scriptPatterns.some((pattern) => lowerContent.includes(pattern))) return false;
57
+ const eventHandlers = [
58
+ "onerror",
59
+ "onload",
60
+ "onclick",
61
+ "onmouseover",
62
+ "onfocus",
63
+ "onblur",
64
+ "oninput"
65
+ ];
66
+ if (eventHandlers.some((handler) => lowerContent.includes(handler))) return false;
67
+ const protocolPatterns = [
68
+ "javascript:",
69
+ "data:text/html",
70
+ "data:text/javascript",
71
+ "data:application",
72
+ "vbscript:",
73
+ "file:///",
74
+ "steam://",
75
+ "slack://"
76
+ ];
77
+ if (protocolPatterns.some((pattern) => lowerContent.includes(pattern))) return false;
78
+ const encodedPatterns = [
79
+ "&#60;script",
80
+ // &#60; = <
81
+ "%3cscript",
82
+ // %3c = <
83
+ "\\x3cscript",
84
+ // \x3c = <
85
+ "\\u003cscript"
86
+ // \u003c = <
87
+ ];
88
+ if (encodedPatterns.some((pattern) => lowerContent.includes(pattern))) return false;
89
+ if (lowerContent.includes("<svg") && lowerContent.includes("onload")) return false;
90
+ if (lowerContent.includes("<iframe")) return false;
91
+ return true;
92
+ }
93
+ export {
94
+ isValidFilePath,
95
+ isValidFileSize,
96
+ isValidTextContent
97
+ };
98
+ //# sourceMappingURL=validators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/validators.ts"],"sourcesContent":["/**\n * File and security validators\n *\n * This module provides validation functions for file operations and content security.\n * Functions implement basic security checks to prevent common attack vectors:\n * - Path traversal attacks (../, ..\\)\n * - XSS injection (script tags, javascript: URLs)\n * - File size limits\n *\n * ⚠️ WARNING: These are basic validations. For production systems, consider:\n * - Additional OS-specific path validation\n * - Symbolic link resolution checking\n * - Comprehensive XSS prevention libraries (e.g., DOMPurify)\n * - Content-Type validation\n * - Virus scanning for uploaded files\n */\n\n/**\n * Validates file path for security vulnerabilities\n *\n * Protects against common path traversal attacks by checking for:\n * - Parent directory references (../, ..\\)\n * - Mixed path separators (//\\, \\\\)\n * - Excessive path length (>1000 chars)\n * - Empty or null paths\n *\n * ⚠️ SECURITY NOTE: This is basic validation. For production use, consider:\n * - Validating against an allowed directory whitelist\n * - Resolving symbolic links\n * - OS-specific path rules (Windows vs Unix)\n * - Canonicalization before validation\n *\n * @param filePath - File path string to validate\n * @returns True if path appears safe, false if potentially dangerous\n *\n * @example\n * ```typescript\n * // Safe paths - Allowed\n * isValidFilePath('./data/users.json') // true\n * isValidFilePath('data/users.json') // true\n * isValidFilePath('/absolute/path/file.txt') // true\n * isValidFilePath('C:\\\\Users\\\\data\\\\file.txt') // true\n *\n * // Dangerous paths - Path traversal attacks\n * isValidFilePath('../../../etc/passwd') // false\n * isValidFilePath('data/../../../etc/passwd') // false\n * isValidFilePath('..\\\\..\\\\..\\\\windows\\\\system32\\\\config') // false\n * isValidFilePath('data//\\\\..//config') // false\n *\n * // Invalid paths - Malformed\n * isValidFilePath('') // false\n * isValidFilePath(null as any) // false\n * isValidFilePath(undefined as any) // false\n * isValidFilePath('x'.repeat(1001)) // false (too long)\n *\n * // Real-world usage in file operations\n * async function readUserFile(userPath: string) {\n * if (!isValidFilePath(userPath)) {\n * throw new Error('Invalid or unsafe file path detected')\n * }\n *\n * // Additional check: ensure path is within allowed directory\n * const allowedDir = '/var/app/uploads'\n * const fullPath = path.join(allowedDir, userPath)\n *\n * return fs.readFile(fullPath, 'utf-8')\n * }\n * ```\n *\n * @see {@link isValidTextContent} for content security validation\n * @see {@link isValidFileSize} for file size validation\n */\nexport function isValidFilePath(filePath: string): boolean {\n // ✅ Type and null checks\n if (!filePath || typeof filePath !== 'string') return false\n\n // ✅ Handle type coercion attempts\n if (typeof filePath === 'object') return false\n\n // ✅ Length limits (DoS prevention)\n if (filePath.length === 0 || filePath.length > 1000) return false\n\n // ✅ Path traversal patterns (Unix and Windows)\n // Reject parent directory traversal (..)\n if (filePath.includes('../') || filePath.includes('..\\\\')) return false\n\n // Reject mixed/double slashes (but allow ./ and .\\ at start for relative paths)\n const suspiciousPatterns = ['//', '\\\\\\\\', '//\\\\', '\\\\//', '/./', '\\\\.\\\\']\n if (suspiciousPatterns.some(pattern => filePath.includes(pattern))) return false\n\n // ✅ URL-encoded path traversal\n const encodedPatterns = [\n '%2e%2e%2f', // ../\n '%2e%2e/', // ../\n '%2e%2e%5c', // ..\\\n '%252e', // double-encoded\n ]\n if (encodedPatterns.some(pattern => filePath.toLowerCase().includes(pattern))) return false\n\n // ✅ Null byte injection\n if (filePath.includes('\\x00')) return false\n\n // ✅ Command injection characters\n const commandChars = [';', '&', '|', '`', '$', '(', ')', '{', '}']\n if (commandChars.some(char => filePath.includes(char))) return false\n\n // ✅ SQL injection attempts\n const sqlPatterns = [\"'\", '\"', '--', '/*', '*/', 'DROP', 'DELETE', 'UNION', 'SELECT']\n const lowerPath = filePath.toLowerCase()\n if (\n sqlPatterns.some(\n pattern =>\n lowerPath.includes(pattern.toLowerCase()) &&\n (pattern === \"'\" || pattern === '\"' || lowerPath.includes(` ${pattern.toLowerCase()}`))\n )\n )\n return false\n\n // ✅ Unicode attacks (RTL override, zero-width)\n const dangerousUnicode = [\n '\\u202E', // Right-to-left override\n '\\u200B', // Zero-width space\n '\\u200C', // Zero-width non-joiner\n '\\u200D', // Zero-width joiner\n '\\uFEFF', // Zero-width no-break space\n ]\n if (dangerousUnicode.some(char => filePath.includes(char))) return false\n\n // ✅ Absolute Windows paths trying to escape\n if (/^[A-Za-z]:\\\\.*\\\\\\.\\./.test(filePath)) return false\n\n return true\n}\n\n/**\n * Validates file size against a maximum limit\n *\n * Checks if a file size is valid (non-negative) and within acceptable limits.\n * Used to prevent:\n * - Denial of Service (DoS) attacks via large file uploads\n * - Disk space exhaustion\n * - Memory overflow during file processing\n *\n * @param size - File size in bytes to validate\n * @param maxSize - Maximum allowed size in bytes\n * @returns True if size is valid and within limit, false otherwise\n *\n * @example\n * ```typescript\n * // Common size limits\n * const KB = 1024\n * const MB = 1024 * KB\n * const GB = 1024 * MB\n *\n * // Image upload validation (5 MB limit)\n * const imageSize = 4 * MB\n * isValidFileSize(imageSize, 5 * MB) // true\n *\n * // Document upload validation (10 MB limit)\n * const docSize = 12 * MB\n * isValidFileSize(docSize, 10 * MB) // false (exceeds limit)\n *\n * // Video upload validation (1 GB limit)\n * const videoSize = 500 * MB\n * isValidFileSize(videoSize, 1 * GB) // true\n *\n * // Invalid sizes\n * isValidFileSize(-100, 1 * MB) // false (negative size)\n * isValidFileSize(NaN, 1 * MB) // false (invalid number)\n * isValidFileSize('1000' as any, 1 * MB) // false (not a number)\n *\n * // Real-world usage in file upload handler\n * app.post('/upload', (req, res) => {\n * const file = req.files.document\n * const maxSize = 10 * 1024 * 1024 // 10 MB\n *\n * if (!isValidFileSize(file.size, maxSize)) {\n * return res.status(413).json({\n * error: 'File too large',\n * maxSize: '10 MB',\n * received: `${(file.size / (1024 * 1024)).toFixed(2)} MB`\n * })\n * }\n *\n * // Process file...\n * })\n * ```\n *\n * @see {@link isValidFilePath} for path security validation\n */\nexport function isValidFileSize(size: number, maxSize: number): boolean {\n return typeof size === 'number' && size >= 0 && size <= maxSize\n}\n\n/**\n * Validates text content for security vulnerabilities and size limits\n *\n * Performs basic security checks on text content to detect common XSS attack vectors:\n * - Script tags (<script>)\n * - JavaScript URLs (javascript:)\n * - Data URLs with HTML (data:text/html)\n * - VBScript URLs (vbscript:)\n *\n * Also enforces maximum content length to prevent DoS attacks.\n *\n * ⚠️ WARNING: This is basic XSS detection. For production systems:\n * - Use dedicated sanitization libraries (DOMPurify, sanitize-html)\n * - Implement Content Security Policy (CSP)\n * - Apply output encoding based on context (HTML, JS, URL)\n * - Validate against allowlists, not just blocklists\n *\n * @param content - Text content to validate\n * @param options - Validation options\n * @param options.maxLength - Maximum content length in characters (default: 1,000,000)\n * @returns True if content appears safe, false if dangerous patterns detected\n *\n * @example\n * ```typescript\n * // Safe content - Allowed\n * isValidTextContent('Hello, world!') // true\n * isValidTextContent('User input: <b>bold</b>') // true\n * isValidTextContent('Email: user@example.com') // true\n *\n * // Dangerous content - XSS vectors detected\n * isValidTextContent('<script>alert(\"XSS\")</script>') // false\n * isValidTextContent('<img src=x onerror=\"alert(1)\">') // false (contains 'script' in onerror)\n * isValidTextContent('<a href=\"javascript:void(0)\">') // false\n * isValidTextContent('<iframe src=\"data:text/html,...\"') // false\n * isValidTextContent('vbscript:msgbox(\"XSS\")') // false\n *\n * // Size limit validation\n * isValidTextContent('x'.repeat(999_999)) // true (under default 1M limit)\n * isValidTextContent('x'.repeat(1_000_001)) // false (exceeds default limit)\n * isValidTextContent('x'.repeat(5000), { maxLength: 1000 }) // false (custom limit)\n *\n * // Edge cases\n * isValidTextContent('') // true (empty is valid)\n * isValidTextContent(null as any) // false (not a string)\n * isValidTextContent(undefined as any) // false (not a string)\n * isValidTextContent(123 as any) // false (not a string)\n *\n * // Real-world usage in comment system\n * app.post('/api/comments', (req, res) => {\n * const { content } = req.body\n *\n * if (!isValidTextContent(content, { maxLength: 5000 })) {\n * return res.status(400).json({\n * error: 'Invalid comment content',\n * details: 'Content contains dangerous patterns or exceeds 5000 characters'\n * })\n * }\n *\n * // Additional sanitization recommended\n * const sanitized = DOMPurify.sanitize(content)\n *\n * // Save to database...\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Form validation with custom limits\n * function validateUserBio(bio: string): { valid: boolean; error?: string } {\n * if (!isValidTextContent(bio, { maxLength: 500 })) {\n * return {\n * valid: false,\n * error: 'Bio must be less than 500 characters and cannot contain scripts'\n * }\n * }\n * return { valid: true }\n * }\n * ```\n *\n * @see {@link isValidFilePath} for file path validation\n * @see sanitizeHtml from validation module for HTML sanitization\n */\nexport function isValidTextContent(content: string, options: { maxLength?: number } = {}): boolean {\n const { maxLength = 1_000_000 } = options\n\n // ✅ Type validation\n if (typeof content !== 'string') return false\n\n // ✅ Length validation (DoS prevention)\n if (content.length > maxLength) return false\n\n const lowerContent = content.toLowerCase()\n\n // ✅ Script tag detection (case-insensitive, with variants)\n const scriptPatterns = ['<script', '</script', '<scr<script>ipt', '<scr\\x00ipt']\n if (scriptPatterns.some(pattern => lowerContent.includes(pattern))) return false\n\n // ✅ Event handler attributes (XSS vectors)\n const eventHandlers = [\n 'onerror',\n 'onload',\n 'onclick',\n 'onmouseover',\n 'onfocus',\n 'onblur',\n 'oninput',\n ]\n if (eventHandlers.some(handler => lowerContent.includes(handler))) return false\n\n // ✅ Protocol handlers (javascript:, data:, vbscript:, file:)\n const protocolPatterns = [\n 'javascript:',\n 'data:text/html',\n 'data:text/javascript',\n 'data:application',\n 'vbscript:',\n 'file:///',\n 'steam://',\n 'slack://',\n ]\n if (protocolPatterns.some(pattern => lowerContent.includes(pattern))) return false\n\n // ✅ Encoded script attempts\n const encodedPatterns = [\n '&#60;script', // &#60; = <\n '%3cscript', // %3c = <\n '\\\\x3cscript', // \\x3c = <\n '\\\\u003cscript', // \\u003c = <\n ]\n if (encodedPatterns.some(pattern => lowerContent.includes(pattern))) return false\n\n // ✅ SVG-based XSS\n if (lowerContent.includes('<svg') && lowerContent.includes('onload')) return false\n\n // ✅ iframe injection\n if (lowerContent.includes('<iframe')) return false\n\n return true\n}\n"],"mappings":";;;AAwEO,SAAS,gBAAgB,UAA2B;AAEzD,MAAI,CAAC,YAAY,OAAO,aAAa,SAAU,QAAO;AAGtD,MAAI,OAAO,aAAa,SAAU,QAAO;AAGzC,MAAI,SAAS,WAAW,KAAK,SAAS,SAAS,IAAM,QAAO;AAI5D,MAAI,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO;AAGlE,QAAM,qBAAqB,CAAC,MAAM,QAAQ,QAAQ,QAAQ,OAAO,OAAO;AACxE,MAAI,mBAAmB,KAAK,aAAW,SAAS,SAAS,OAAO,CAAC,EAAG,QAAO;AAG3E,QAAM,kBAAkB;AAAA,IACtB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AACA,MAAI,gBAAgB,KAAK,aAAW,SAAS,YAAY,EAAE,SAAS,OAAO,CAAC,EAAG,QAAO;AAGtF,MAAI,SAAS,SAAS,IAAM,EAAG,QAAO;AAGtC,QAAM,eAAe,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AACjE,MAAI,aAAa,KAAK,UAAQ,SAAS,SAAS,IAAI,CAAC,EAAG,QAAO;AAG/D,QAAM,cAAc,CAAC,KAAK,KAAK,MAAM,MAAM,MAAM,QAAQ,UAAU,SAAS,QAAQ;AACpF,QAAM,YAAY,SAAS,YAAY;AACvC,MACE,YAAY;AAAA,IACV,aACE,UAAU,SAAS,QAAQ,YAAY,CAAC,MACvC,YAAY,OAAO,YAAY,OAAO,UAAU,SAAS,IAAI,QAAQ,YAAY,CAAC,EAAE;AAAA,EACzF;AAEA,WAAO;AAGT,QAAM,mBAAmB;AAAA,IACvB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AACA,MAAI,iBAAiB,KAAK,UAAQ,SAAS,SAAS,IAAI,CAAC,EAAG,QAAO;AAGnE,MAAI,uBAAuB,KAAK,QAAQ,EAAG,QAAO;AAElD,SAAO;AACT;AA0DO,SAAS,gBAAgB,MAAc,SAA0B;AACtE,SAAO,OAAO,SAAS,YAAY,QAAQ,KAAK,QAAQ;AAC1D;AAoFO,SAAS,mBAAmB,SAAiB,UAAkC,CAAC,GAAY;AACjG,QAAM,EAAE,YAAY,IAAU,IAAI;AAGlC,MAAI,OAAO,YAAY,SAAU,QAAO;AAGxC,MAAI,QAAQ,SAAS,UAAW,QAAO;AAEvC,QAAM,eAAe,QAAQ,YAAY;AAGzC,QAAM,iBAAiB,CAAC,WAAW,aAAY,mBAAmB,WAAa;AAC/E,MAAI,eAAe,KAAK,aAAW,aAAa,SAAS,OAAO,CAAC,EAAG,QAAO;AAG3E,QAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,cAAc,KAAK,aAAW,aAAa,SAAS,OAAO,CAAC,EAAG,QAAO;AAG1E,QAAM,mBAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,iBAAiB,KAAK,aAAW,aAAa,SAAS,OAAO,CAAC,EAAG,QAAO;AAG7E,QAAM,kBAAkB;AAAA,IACtB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AACA,MAAI,gBAAgB,KAAK,aAAW,aAAa,SAAS,OAAO,CAAC,EAAG,QAAO;AAG5E,MAAI,aAAa,SAAS,MAAM,KAAK,aAAa,SAAS,QAAQ,EAAG,QAAO;AAG7E,MAAI,aAAa,SAAS,SAAS,EAAG,QAAO;AAE7C,SAAO;AACT;","names":[]}
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/async.ts
21
+ var async_exports = {};
22
+ __export(async_exports, {
23
+ handleOperation: () => handleOperation,
24
+ runBatch: () => runBatch,
25
+ sleep: () => sleep,
26
+ wait: () => wait
27
+ });
28
+ module.exports = __toCommonJS(async_exports);
29
+
30
+ // src/errors.ts
31
+ var TsHelpersError = class _TsHelpersError extends Error {
32
+ constructor(message, options = {}) {
33
+ super(message);
34
+ this.name = "TsHelpersError";
35
+ this.code = options.code;
36
+ this.data = options.data;
37
+ this.cause = options.cause;
38
+ if (Error.captureStackTrace) {
39
+ Error.captureStackTrace(this, _TsHelpersError);
40
+ }
41
+ }
42
+ };
43
+
44
+ // src/async.ts
45
+ var sleep = (ms) => {
46
+ return new Promise((resolve) => setTimeout(resolve, ms));
47
+ };
48
+ var wait = (ms) => sleep(ms);
49
+ async function runBatch(jobs, batchSize = 50) {
50
+ if (batchSize <= 0) {
51
+ throw new TsHelpersError("Batch size must be greater than 0", {
52
+ code: "INVALID_OPERATION" /* INVALID_OPERATION */,
53
+ data: { batchSize }
54
+ });
55
+ }
56
+ const results = [];
57
+ const batches = Math.ceil(jobs.length / batchSize);
58
+ for (let i = 0; i < batches; i++) {
59
+ const batchStart = i * batchSize;
60
+ const batchEnd = batchStart + batchSize;
61
+ const batch = jobs.slice(batchStart, batchEnd);
62
+ const batchResults = await Promise.all(batch.map((job) => job));
63
+ results.push(...batchResults);
64
+ }
65
+ return results;
66
+ }
67
+ function handleOperation(target, operation, ...args) {
68
+ if (operation.includes("/")) {
69
+ const [parentOp, childOp] = operation.split("/");
70
+ if (!target[parentOp] || !target[parentOp][childOp]) {
71
+ throw new TsHelpersError(`Operation [${operation}] does not exist`, {
72
+ code: "INVALID_OPERATION" /* INVALID_OPERATION */,
73
+ data: { operation, parentOp, childOp }
74
+ });
75
+ }
76
+ return target[parentOp][childOp](...args);
77
+ }
78
+ if (!target[operation]) {
79
+ throw new TsHelpersError(`Operation [${operation}] does not exist`, {
80
+ code: "INVALID_OPERATION" /* INVALID_OPERATION */,
81
+ data: { operation }
82
+ });
83
+ }
84
+ return target[operation](...args);
85
+ }
86
+ //# sourceMappingURL=async.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/async.ts","../../src/errors.ts"],"sourcesContent":["/**\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC2EO,IAAM,iBAAN,MAAM,wBAAuB,MAAM;AAAA,EAKxC,YAAY,SAAiB,UAAiC,CAAC,GAAG;AAChE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO,QAAQ;AACpB,SAAK,OAAO,QAAQ;AACpB,SAAK,QAAQ,QAAQ;AAErB,QAAI,MAAM,mBAAmB;AAC3B,YAAM,kBAAkB,MAAM,eAAc;AAAA,IAC9C;AAAA,EACF;AACF;;;ADyBO,IAAM,QAAQ,CAAC,OAA8B;AAClD,SAAO,IAAI,QAAQ,aAAW,WAAW,SAAS,EAAE,CAAC;AACvD;AAsBO,IAAM,OAAO,CAAC,OAA8B,MAAM,EAAE;AA0I3D,eAAsB,SAAY,MAAoB,YAAoB,IAAkB;AAC1F,MAAI,aAAa,GAAG;AAClB,UAAM,IAAI,eAAe,qCAAqC;AAAA,MAC5D;AAAA,MACA,MAAM,EAAE,UAAU;AAAA,IACpB,CAAC;AAAA,EACH;AAEA,QAAM,UAAe,CAAC;AACtB,QAAM,UAAU,KAAK,KAAK,KAAK,SAAS,SAAS;AAEjD,WAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,UAAM,aAAa,IAAI;AACvB,UAAM,WAAW,aAAa;AAC9B,UAAM,QAAQ,KAAK,MAAM,YAAY,QAAQ;AAE7C,UAAM,eAAe,MAAM,QAAQ,IAAI,MAAM,IAAI,SAAO,GAAG,CAAC;AAC5D,YAAQ,KAAK,GAAG,YAAY;AAAA,EAC9B;AAEA,SAAO;AACT;AA0LO,SAAS,gBACd,QACA,cACG,MACS;AACZ,MAAI,UAAU,SAAS,GAAG,GAAG;AAC3B,UAAM,CAAC,UAAU,OAAO,IAAI,UAAU,MAAM,GAAG;AAE/C,QAAI,CAAC,OAAO,QAAQ,KAAK,CAAC,OAAO,QAAQ,EAAE,OAAO,GAAG;AACnD,YAAM,IAAI,eAAe,cAAc,SAAS,oBAAoB;AAAA,QAClE;AAAA,QACA,MAAM,EAAE,WAAW,UAAU,QAAQ;AAAA,MACvC,CAAC;AAAA,IACH;AAEA,WAAO,OAAO,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI;AAAA,EAC1C;AAEA,MAAI,CAAC,OAAO,SAAS,GAAG;AACtB,UAAM,IAAI,eAAe,cAAc,SAAS,oBAAoB;AAAA,MAClE;AAAA,MACA,MAAM,EAAE,UAAU;AAAA,IACpB,CAAC;AAAA,EACH;AAEA,SAAO,OAAO,SAAS,EAAE,GAAG,IAAI;AAClC;","names":[]}
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/dates.ts
31
+ var dates_exports = {};
32
+ __export(dates_exports, {
33
+ addDays: () => addDays,
34
+ addMonths: () => addMonths,
35
+ addNowDays: () => addNowDays,
36
+ addNowMonths: () => addNowMonths,
37
+ addNowSeconds: () => addNowSeconds,
38
+ addNowYears: () => addNowYears,
39
+ addSeconds: () => addSeconds,
40
+ addYears: () => addYears,
41
+ areDatesEqualWithTolerance: () => areDatesEqualWithTolerance,
42
+ dayOfWeek: () => dayOfWeek,
43
+ diffBusinessDays: () => diffBusinessDays,
44
+ diffDays: () => diffDays,
45
+ diffMilliSeconds: () => diffMilliSeconds,
46
+ diffMonths: () => diffMonths,
47
+ diffYears: () => diffYears,
48
+ excelToDate: () => excelToDate,
49
+ format: () => format,
50
+ formatForMysql: () => formatForMysql,
51
+ formatNow: () => formatNow,
52
+ fromNow: () => fromNow,
53
+ getFirstDayOfYear: () => getFirstDayOfYear,
54
+ getFirstWorkdayAfterMonths: () => getFirstWorkdayAfterMonths,
55
+ getFirstWorkdayOfMonth: () => getFirstWorkdayOfMonth,
56
+ getLastDayOfYear: () => getLastDayOfYear,
57
+ getLastWorkdayOfMonth: () => getLastWorkdayOfMonth,
58
+ isDateTime: () => isDateTime,
59
+ isEqualsDateTimeByDay: () => isEqualsDateTimeByDay,
60
+ isExpired: () => isExpired,
61
+ isNew: () => isNew,
62
+ isWeekday: () => isWeekday,
63
+ longString: () => longString,
64
+ now: () => now,
65
+ toDate: () => toDate,
66
+ toDateFromString: () => toDateFromString,
67
+ toISO: () => toISO,
68
+ weekOfYear: () => weekOfYear
69
+ });
70
+ module.exports = __toCommonJS(dates_exports);
71
+ var import_dayjs = __toESM(require("dayjs"));
72
+ var import_utc = __toESM(require("dayjs/plugin/utc.js"));
73
+ var import_relativeTime = __toESM(require("dayjs/plugin/relativeTime.js"));
74
+ var import_weekOfYear = __toESM(require("dayjs/plugin/weekOfYear.js"));
75
+ var import_customParseFormat = __toESM(require("dayjs/plugin/customParseFormat.js"));
76
+ var import_isSameOrAfter = __toESM(require("dayjs/plugin/isSameOrAfter.js"));
77
+ var import_isSameOrBefore = __toESM(require("dayjs/plugin/isSameOrBefore.js"));
78
+ var import_weekday = __toESM(require("dayjs/plugin/weekday.js"));
79
+ var import_localeData = __toESM(require("dayjs/plugin/localeData.js"));
80
+ var import_localizedFormat = __toESM(require("dayjs/plugin/localizedFormat.js"));
81
+ var import_es = require("dayjs/locale/es.js");
82
+ var dateValidator = __toESM(require("iso-datestring-validator"));
83
+ var { isValidDate, isValidISODateString } = dateValidator;
84
+ import_dayjs.default.extend(import_utc.default);
85
+ import_dayjs.default.extend(import_relativeTime.default);
86
+ import_dayjs.default.extend(import_weekOfYear.default);
87
+ import_dayjs.default.extend(import_customParseFormat.default);
88
+ import_dayjs.default.extend(import_isSameOrAfter.default);
89
+ import_dayjs.default.extend(import_isSameOrBefore.default);
90
+ import_dayjs.default.extend(import_weekday.default);
91
+ import_dayjs.default.extend(import_localeData.default);
92
+ import_dayjs.default.extend(import_localizedFormat.default);
93
+ import_dayjs.default.locale("es");
94
+ var formatNow = (formatStr = "DD/MM/YYYY") => (0, import_dayjs.default)().format(formatStr);
95
+ var format = (value, formatStr = "DD/MM/YYYY") => {
96
+ if (!value) return "";
97
+ if (formatStr.toLowerCase() === "gg") return weekOfYear(value);
98
+ else if (formatStr.toLowerCase() === "gggg") return (0, import_dayjs.default)(value).format("YY") + weekOfYear(value);
99
+ return (0, import_dayjs.default)(value).format(formatStr);
100
+ };
101
+ var longString = (value = null) => {
102
+ if (!value) return "";
103
+ return (0, import_dayjs.default)(value).format("LL");
104
+ };
105
+ var toDate = (value, isUtc) => {
106
+ if (isUtc === void 0) return (0, import_dayjs.default)(value).toDate();
107
+ return isUtc ? import_dayjs.default.utc(value).toDate() : (0, import_dayjs.default)(value).toDate();
108
+ };
109
+ var toDateFromString = (dateString, format2) => {
110
+ const formatRegex = {
111
+ "DD/MM/YYYY": /^(\d{2})\/(\d{2})\/(\d{4})$/,
112
+ "YYYY-MM-DD": /^(\d{4})-(\d{2})-(\d{2})$/,
113
+ "MM/DD/YYYY": /^(\d{2})\/(\d{2})\/(\d{4})$/,
114
+ "YYYY/MM/DD": /^(\d{4})\/(\d{2})\/(\d{2})$/,
115
+ "DD-MM-YYYY": /^(\d{2})-(\d{2})-(\d{4})$/,
116
+ "MM-DD-YYYY": /^(\d{2})-(\d{2})-(\d{4})$/,
117
+ YYYYMMDD: /^(\d{4})(\d{2})(\d{2})$/,
118
+ DDMMYYYY: /^(\d{2})(\d{2})(\d{4})$/,
119
+ MMDDYYYY: /^(\d{2})(\d{2})(\d{4})$/,
120
+ "YYYY.MM.DD": /^(\d{4})\.(\d{2})\.(\d{2})$/,
121
+ "DD.MM.YYYY": /^(\d{2})\.(\d{2})\.(\d{4})$/,
122
+ "MM.DD.YYYY": /^(\d{2})\.(\d{2})\.(\d{4})$/
123
+ };
124
+ const regex = formatRegex[format2];
125
+ if (!regex) return null;
126
+ const match = dateString.match(regex);
127
+ if (match) {
128
+ let year, month, day;
129
+ if (format2.startsWith("YYYY")) {
130
+ year = parseInt(match[1], 10);
131
+ month = parseInt(match[2], 10) - 1;
132
+ day = parseInt(match[3], 10);
133
+ } else if (format2.startsWith("DD")) {
134
+ day = parseInt(match[1], 10);
135
+ month = parseInt(match[2], 10) - 1;
136
+ year = parseInt(match[3], 10);
137
+ } else if (format2.startsWith("MM")) {
138
+ month = parseInt(match[1], 10) - 1;
139
+ day = parseInt(match[2], 10);
140
+ year = parseInt(match[3], 10);
141
+ } else {
142
+ return null;
143
+ }
144
+ return new Date(year, month, day);
145
+ }
146
+ return null;
147
+ };
148
+ var now = () => (0, import_dayjs.default)().toDate();
149
+ var isNew = (value, daysnew = 1) => (0, import_dayjs.default)().isSameOrBefore((0, import_dayjs.default)(value).add(daysnew, "days"));
150
+ var toISO = (value = null, isUtc = false) => {
151
+ if (!value) return (0, import_dayjs.default)().toISOString();
152
+ return isUtc ? import_dayjs.default.utc(value).toISOString() : (0, import_dayjs.default)(value).toISOString();
153
+ };
154
+ var fromNow = (value) => (0, import_dayjs.default)(value).fromNow();
155
+ var dayOfWeek = (value = null) => {
156
+ if (!value) return (0, import_dayjs.default)().format("d");
157
+ return (0, import_dayjs.default)(value).format("d");
158
+ };
159
+ var weekOfYear = (value = null) => {
160
+ if (!value) return (0, import_dayjs.default)().locale("es").week().toString().padStart(2, "0");
161
+ return (0, import_dayjs.default)(value).locale("es").week().toString().padStart(2, "0");
162
+ };
163
+ var diffDays = (start, end = null, precise = false) => {
164
+ const v2 = !end ? (0, import_dayjs.default)() : (0, import_dayjs.default)(end);
165
+ return (0, import_dayjs.default)(start).diff(v2, "days", precise);
166
+ };
167
+ var diffBusinessDays = (start, end = null, precise = false) => {
168
+ let startDate = (0, import_dayjs.default)(start).startOf("day");
169
+ let endDate = end ? (0, import_dayjs.default)(end).startOf("day") : (0, import_dayjs.default)().startOf("day");
170
+ if (startDate.isAfter(endDate)) {
171
+ ;
172
+ [startDate, endDate] = [endDate, startDate];
173
+ }
174
+ let businessDays = 0;
175
+ let currentDate = startDate;
176
+ while (currentDate.isBefore(endDate)) {
177
+ if (isWeekday(currentDate)) {
178
+ businessDays++;
179
+ }
180
+ currentDate = currentDate.add(1, "day");
181
+ }
182
+ if (precise) {
183
+ const fractionalDay = endDate.diff(currentDate, "hours") / 24;
184
+ businessDays += fractionalDay;
185
+ }
186
+ return businessDays;
187
+ };
188
+ var diffMonths = (value, valueRefOrNow = null, precise = false) => {
189
+ const v2 = !valueRefOrNow ? (0, import_dayjs.default)() : (0, import_dayjs.default)(valueRefOrNow);
190
+ return (0, import_dayjs.default)(value).diff(v2, "months", precise);
191
+ };
192
+ var diffYears = (value, valueRefOrNow = null, precise = false) => {
193
+ const v2 = !valueRefOrNow ? (0, import_dayjs.default)() : (0, import_dayjs.default)(valueRefOrNow);
194
+ return (0, import_dayjs.default)(value).diff(v2, "years", precise);
195
+ };
196
+ var diffMilliSeconds = (value, valueRefOrNow = null) => {
197
+ const v2 = !valueRefOrNow ? (0, import_dayjs.default)() : (0, import_dayjs.default)(valueRefOrNow);
198
+ return (0, import_dayjs.default)(value).diff(v2, "milliseconds", true);
199
+ };
200
+ var addDays = (value, nDays = 1) => (0, import_dayjs.default)(value).add(nDays, "days").toDate();
201
+ var addSeconds = (value, nSeconds = 1) => (0, import_dayjs.default)(value).add(nSeconds, "seconds").toDate();
202
+ var areDatesEqualWithTolerance = (date1, date2) => {
203
+ const tolerance = 2 * 1e3;
204
+ return Math.abs((0, import_dayjs.default)(date1).diff((0, import_dayjs.default)(date2))) <= tolerance;
205
+ };
206
+ var addNowDays = (nDays = 1) => (0, import_dayjs.default)().add(nDays, "days").toDate();
207
+ var addNowSeconds = (nSeconds = 60) => (0, import_dayjs.default)().add(nSeconds, "seconds").toDate();
208
+ var addMonths = (value, nMonths = 1) => (0, import_dayjs.default)(value).add(nMonths, "months").toDate();
209
+ var addNowMonths = (nMonths = 1) => (0, import_dayjs.default)().add(nMonths, "months").toDate();
210
+ var addYears = (value, nYears = 1) => (0, import_dayjs.default)(value).add(nYears, "years").toDate();
211
+ var addNowYears = (nYears = 1) => (0, import_dayjs.default)().add(nYears, "years").toDate();
212
+ var excelToDate = (value) => {
213
+ try {
214
+ const d = Number(value);
215
+ if (d >= 18e3 && d <= 3e5) return new Date(Math.round((d - 25569) * 86400 * 1e3));
216
+ return null;
217
+ } catch (_err) {
218
+ return null;
219
+ }
220
+ };
221
+ var isDateTime = (value) => {
222
+ try {
223
+ if (!value) return false;
224
+ if (typeof value === "number") return false;
225
+ else if (typeof value === "boolean") return false;
226
+ else if (typeof value === "string" && !isValidISODateString(value) && !isValidDate(value) && !isValidDate(value, ""))
227
+ return false;
228
+ else if (typeof value === "object" && !(value instanceof Date) && !import_dayjs.default.isDayjs(value))
229
+ return false;
230
+ return (0, import_dayjs.default)(value).isValid();
231
+ } catch (_err) {
232
+ return false;
233
+ }
234
+ };
235
+ var isEqualsDateTimeByDay = (value1, value2) => {
236
+ if (!isDateTime(value1)) return false;
237
+ if (!isDateTime(value2)) return false;
238
+ return (0, import_dayjs.default)(value1).isSame((0, import_dayjs.default)(value2), "day");
239
+ };
240
+ var isExpired = (value, valueRefOrNow = null) => {
241
+ const v2 = !valueRefOrNow ? (0, import_dayjs.default)() : (0, import_dayjs.default)(valueRefOrNow);
242
+ if (isDateTime(value)) {
243
+ return v2.isAfter(value);
244
+ }
245
+ return true;
246
+ };
247
+ var formatForMysql = (fecha) => {
248
+ if (!fecha) return null;
249
+ fecha.setMinutes(fecha.getMinutes() - fecha.getTimezoneOffset());
250
+ return fecha.toISOString().slice(0, 19).replace("T", " ");
251
+ };
252
+ var getFirstWorkdayOfMonth = (month) => {
253
+ const monthToUse = month === void 0 ? (0, import_dayjs.default)().month() : month;
254
+ let firstDay = (0, import_dayjs.default)().month(monthToUse).startOf("month");
255
+ while (firstDay.day() === 0 || firstDay.day() === 6) {
256
+ firstDay = firstDay.add(1, "day");
257
+ }
258
+ return firstDay.toDate();
259
+ };
260
+ var getLastWorkdayOfMonth = (month) => {
261
+ const monthToUse = month === void 0 ? (0, import_dayjs.default)().month() : month;
262
+ let lastDay = (0, import_dayjs.default)().month(monthToUse).endOf("month");
263
+ while (lastDay.day() === 0 || lastDay.day() === 6) {
264
+ lastDay = lastDay.subtract(1, "day");
265
+ }
266
+ return lastDay.toDate();
267
+ };
268
+ var getFirstWorkdayAfterMonths = (initialDate, n) => {
269
+ const startDate = (0, import_dayjs.default)(initialDate);
270
+ const monthsToAdd = n;
271
+ const targetDate = startDate.add(monthsToAdd, "months");
272
+ let firstWorkday = targetDate.startOf("month");
273
+ while (firstWorkday.day() === 0 || firstWorkday.day() === 6) {
274
+ firstWorkday = firstWorkday.add(1, "day");
275
+ }
276
+ return firstWorkday.toDate();
277
+ };
278
+ var getFirstDayOfYear = () => (0, import_dayjs.default)().startOf("year").toDate();
279
+ var getLastDayOfYear = () => (0, import_dayjs.default)().endOf("year").toDate();
280
+ var isWeekday = (date) => {
281
+ const d = (0, import_dayjs.default)(date);
282
+ const dayOfWeek2 = d.day();
283
+ return dayOfWeek2 !== 0 && dayOfWeek2 !== 6;
284
+ };
285
+ //# sourceMappingURL=dates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/dates.ts"],"sourcesContent":["/**\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"],"mappings":"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","names":["dayjs","utc","relativeTime","weekOfYearPlugin","customParseFormat","isSameOrAfter","isSameOrBefore","weekday","localeData","localizedFormat","format","dayOfWeek"]}