superjs-core 0.3.8 → 0.4.0
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.
- package/README.md +58 -49
- package/dist/collection/index.d.ts +16 -1
- package/dist/collection/index.js +30 -0
- package/dist/collection/index.js.map +1 -1
- package/dist/color/index.d.ts +50 -0
- package/dist/color/index.js +66 -0
- package/dist/color/index.js.map +1 -0
- package/dist/core/index.d.ts +25 -1
- package/dist/core/index.js +51 -0
- package/dist/core/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -1
- package/dist/string/index.d.ts +34 -1
- package/dist/string/index.js +37 -0
- package/dist/string/index.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,24 +1,35 @@
|
|
|
1
1
|
# superjs-core
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **All-in-one JavaScript toolkit — Standard Library + Dependency Scanner + 🇮🇩 Indonesia Validation + Logger + Typed Errors**
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install superjs-core
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
One package for all your JavaScript needs: utility functions, async helpers, crypto, path manipulation, typed errors, structured logging, **plus** dependency health scanner and Indonesia-specific data validation (NIK, NPWP, Phone).
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Features
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
- ✅ **90+ functions** — 16 modules covering everything from `deepClone` to `terbilang`
|
|
16
|
+
- ✅ **Tree-shakeable** — import only what you need via subpath exports
|
|
17
|
+
- ✅ **TypeScript strict** — full type safety, zero `any`
|
|
18
|
+
- ✅ **Zero runtime dependencies** — commander + picocolors are CLI-only
|
|
19
|
+
- ✅ **ESM-first** — target ES2022, optimized for Node 18+ and modern browsers
|
|
20
|
+
- ✅ **Biome linted** — consistent code style enforced
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Modules
|
|
25
|
+
|
|
26
|
+
| Module | Key Functions |
|
|
27
|
+
|--------|---------------|
|
|
17
28
|
| **core** | deepClone, deepMerge, debounce, throttle, memoize, retry, once |
|
|
18
|
-
| **math** | add/sub/mul/div (safe), median, stddev, percentile, correlation, formatCurrency |
|
|
29
|
+
| **math** | add/sub/mul/div (safe float), median, stddev, percentile, correlation, formatCurrency |
|
|
19
30
|
| **date** | formatDate, parseDate, timeAgo, Duration, timezone helpers (WIB/WITA/WIT) |
|
|
20
31
|
| **collection** | sortBy, groupBy, shuffle, topoSort, slidingWindows, chunk |
|
|
21
|
-
| **string** | camelCase, uuid, nanoid, slugify, levenshtein,
|
|
32
|
+
| **string** | camelCase, uuid, nanoid, slugify, levenshtein, fuzzyMatch, maskString |
|
|
22
33
|
| **async** | sleep, parallelMap, Queue, Semaphore, memoizeAsync, retryAsync |
|
|
23
34
|
| **io** | parseCsv, stringifyCsv, safeJsonParse, env, envInt, envBool |
|
|
24
35
|
| **type** | 20+ type guards (isString, isNil, assertDefined, getType) |
|
|
@@ -29,38 +40,49 @@ Satu package untuk semua kebutuhan JavaScript: utility functions, async helpers,
|
|
|
29
40
|
| **logger** | Logger class, child loggers, console/JSON/file transports |
|
|
30
41
|
| **dep-exray** | scanProject, generateReport, analyzeUsage, CLI: `npx dep-exray .` |
|
|
31
42
|
|
|
43
|
+
### 🇮🇩 Indonesian Locale
|
|
44
|
+
|
|
45
|
+
| Function | Description |
|
|
46
|
+
|----------|-------------|
|
|
47
|
+
| `terbilang(value)` | Convert numbers to Indonesian words ("satu juta lima ratus ribu") |
|
|
48
|
+
| `formatRupiah(value)` | Format as Rupiah ("Rp1.500.000") |
|
|
49
|
+
| `isNIK(value)` | Validate Indonesian NIK (16-digit ID number) |
|
|
50
|
+
| `isNPWP(value)` | Validate Indonesian NPWP (tax ID with checksum) |
|
|
51
|
+
| `isPhone(value)` | Validate Indonesian phone numbers |
|
|
52
|
+
|
|
32
53
|
---
|
|
33
54
|
|
|
34
|
-
##
|
|
55
|
+
## Quick Examples
|
|
35
56
|
|
|
36
57
|
```typescript
|
|
37
58
|
import { deepClone, debounce } from "superjs-core"
|
|
38
59
|
import { formatDate, timeAgo } from "superjs-core/date"
|
|
39
60
|
import { groupBy, topoSort } from "superjs-core/collection"
|
|
40
|
-
import {
|
|
61
|
+
import { Queue } from "superjs-core/async"
|
|
41
62
|
import { uuid, maskString, terbilang, formatRupiah } from "superjs-core/string"
|
|
42
63
|
import { generateToken } from "superjs-core/crypto"
|
|
43
64
|
import { isNIK, isNPWP, isPhone } from "superjs-core/validation"
|
|
44
|
-
import { createError
|
|
65
|
+
import { createError } from "superjs-core/error"
|
|
45
66
|
import { Logger } from "superjs-core/logger"
|
|
46
67
|
import { median, stddev, formatCurrency } from "superjs-core/math"
|
|
47
68
|
import { scanProject } from "superjs-core/dep-exray"
|
|
48
69
|
|
|
49
|
-
// Deep clone
|
|
70
|
+
// Deep clone with circular reference support
|
|
50
71
|
const cloned = deepClone({ a: 1, b: { c: new Date() } })
|
|
51
72
|
|
|
52
|
-
// Safe math (0.1 + 0.2 = 0.3)
|
|
73
|
+
// Safe math (0.1 + 0.2 = 0.3 ✅)
|
|
74
|
+
import { add } from "superjs-core/math"
|
|
53
75
|
console.log(add(0.1, 0.2)) // 0.3
|
|
54
76
|
|
|
55
|
-
// Date formatting
|
|
77
|
+
// Date formatting without moment
|
|
56
78
|
console.log(formatDate(new Date(), "DD/MM/YYYY")) // "28/06/2026"
|
|
57
|
-
console.log(timeAgo(new Date(Date.now() - 5000))) // "5
|
|
79
|
+
console.log(timeAgo(new Date(Date.now() - 5000))) // "5 seconds ago"
|
|
58
80
|
|
|
59
|
-
// Priority queue
|
|
81
|
+
// Priority task queue
|
|
60
82
|
const queue = new Queue({ concurrency: 2 })
|
|
61
83
|
await queue.add(() => fetch("/api/data"))
|
|
62
84
|
|
|
63
|
-
//
|
|
85
|
+
// Indonesia validation
|
|
64
86
|
isNIK("3201010203940001") // true
|
|
65
87
|
isNPWP("12.345.678.9-012.344") // true
|
|
66
88
|
isPhone("08123456789") // true
|
|
@@ -68,29 +90,29 @@ isPhone("08123456789") // true
|
|
|
68
90
|
// Indonesian locale
|
|
69
91
|
terbilang(1500000) // "satu juta lima ratus ribu"
|
|
70
92
|
formatRupiah(1500000) // "Rp1.500.000"
|
|
71
|
-
maskString("08123456789") // "081*****789"
|
|
72
93
|
|
|
73
94
|
// Statistics
|
|
74
95
|
median([1, 2, 3, 4, 5]) // 3
|
|
75
96
|
percentile([1, 2, 3, 4, 5], 90) // 4.6
|
|
76
|
-
formatCurrency(1500000, { locale: "
|
|
97
|
+
formatCurrency(1500000, { locale: "en-US", currency: "USD" }) // "$1,500,000"
|
|
77
98
|
|
|
78
99
|
// Typed errors
|
|
79
100
|
throw createError("VALIDATION_ERROR", "Email required", { details: { field: "email" } })
|
|
80
101
|
|
|
81
|
-
//
|
|
102
|
+
// Structured logger
|
|
82
103
|
const log = new Logger({ level: "info", name: "app" })
|
|
83
104
|
log.info("Server started", { port: 3000 })
|
|
84
105
|
|
|
85
106
|
// Dependency scanning
|
|
86
107
|
const report = await scanProject({ path: "./my-project" })
|
|
87
|
-
console.log(report.totalEstimatedSize)
|
|
108
|
+
console.log(report.totalEstimatedSize) // "2.3 MB"
|
|
109
|
+
```
|
|
88
110
|
|
|
89
111
|
---
|
|
90
112
|
|
|
91
113
|
## dep-exray — Dependency Health Scanner (built-in)
|
|
92
114
|
|
|
93
|
-
**Scan project
|
|
115
|
+
**Scan your project to find bloated, unused, or vulnerable dependencies.**
|
|
94
116
|
|
|
95
117
|
```bash
|
|
96
118
|
npx dep-exray .
|
|
@@ -98,32 +120,11 @@ npx dep-exray /path/to/project --json --verbose
|
|
|
98
120
|
```
|
|
99
121
|
|
|
100
122
|
### Features
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
- CVE detection
|
|
104
|
-
- JSON output
|
|
105
|
-
- Usage analyzer —
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## Quick Start
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
git clone <repo-url> superjs
|
|
113
|
-
cd superjs/packages/core
|
|
114
|
-
npm install
|
|
115
|
-
npx tsup # Build
|
|
116
|
-
npx vitest run # Test (757 tests)
|
|
117
|
-
npx dep-exray . # Scan project
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## Test Stats
|
|
123
|
-
|
|
124
|
-
| File | Tests |
|
|
125
|
-
|------|-------|
|
|
126
|
-
| 17 test files | **757** passing |
|
|
123
|
+
- Detect replacements: lodash → superjs-core, moment → superjs-core/date, uuid → native crypto.randomUUID()
|
|
124
|
+
- Estimate dependency size in MB/KB
|
|
125
|
+
- CVE detection from known vulnerability database
|
|
126
|
+
- JSON output for CI/CD integration
|
|
127
|
+
- Usage analyzer — detects whether dependencies are actually imported
|
|
127
128
|
|
|
128
129
|
---
|
|
129
130
|
|
|
@@ -156,9 +157,17 @@ packages/core/
|
|
|
156
157
|
|
|
157
158
|
---
|
|
158
159
|
|
|
160
|
+
## Test Stats
|
|
161
|
+
|
|
162
|
+
| Test Files | Tests |
|
|
163
|
+
|-----------|-------|
|
|
164
|
+
| 17 | **757** passing |
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
159
168
|
## Roadmap
|
|
160
169
|
|
|
161
|
-
|
|
170
|
+
See [ROADMAP.md](./ROADMAP.md) for full details.
|
|
162
171
|
|
|
163
172
|
### Priority
|
|
164
173
|
- **P0 ✅** validation, error, logger modules
|
|
@@ -170,4 +179,4 @@ Lihat [ROADMAP.md](./ROADMAP.md) untuk detail lengkap.
|
|
|
170
179
|
|
|
171
180
|
## License
|
|
172
181
|
|
|
173
|
-
MIT
|
|
182
|
+
MIT
|
|
@@ -77,5 +77,20 @@ declare function topoSort<T extends {
|
|
|
77
77
|
}>(items: T[]): T[];
|
|
78
78
|
declare function slidingWindows<T>(items: T[], size: number, step?: number): T[][];
|
|
79
79
|
declare function tumblingWindows<T>(items: T[], size: number): T[][];
|
|
80
|
+
/**
|
|
81
|
+
* Gets a nested value from an object using a dot-separated path.
|
|
82
|
+
*
|
|
83
|
+
* @example deepGet({ a: { b: 2 } }, 'a.b') // 2
|
|
84
|
+
* @example deepGet({ a: { b: 2 } }, 'a.c') // undefined
|
|
85
|
+
*/
|
|
86
|
+
declare function deepGet<T = unknown>(obj: unknown, path: string, default_?: T): T | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Sets a nested value in an object using a dot-separated path.
|
|
89
|
+
* Creates intermediate objects/arrays as needed.
|
|
90
|
+
*
|
|
91
|
+
* @example deepSet({ a: { b: 2 } }, 'a.b', 3) // { a: { b: 3 } }
|
|
92
|
+
* @example deepSet({}, 'a.b.c', 1) // { a: { b: { c: 1 } } }
|
|
93
|
+
*/
|
|
94
|
+
declare function deepSet<T extends Record<string, unknown>>(obj: T, path: string, value: unknown): T;
|
|
80
95
|
|
|
81
|
-
export { type SortDirection, chunk, first, flatten, groupBy, isEmpty, keyBy, last, omit, orderBy, pick, pluck, sample, sampleSize, shuffle, slidingWindows, sortBy, topoSort, tumblingWindows, uniq, uniqueBy };
|
|
96
|
+
export { type SortDirection, chunk, deepGet, deepSet, first, flatten, groupBy, isEmpty, keyBy, last, omit, orderBy, pick, pluck, sample, sampleSize, shuffle, slidingWindows, sortBy, topoSort, tumblingWindows, uniq, uniqueBy };
|
package/dist/collection/index.js
CHANGED
|
@@ -170,8 +170,38 @@ function tumblingWindows(items, size) {
|
|
|
170
170
|
}
|
|
171
171
|
return result;
|
|
172
172
|
}
|
|
173
|
+
function deepGet(obj, path, default_) {
|
|
174
|
+
const keys = path.split(".");
|
|
175
|
+
let current = obj;
|
|
176
|
+
for (const key of keys) {
|
|
177
|
+
if (current === null || current === void 0) return default_;
|
|
178
|
+
if (typeof current !== "object") return default_;
|
|
179
|
+
const curObj = current;
|
|
180
|
+
if (!(key in curObj)) return default_;
|
|
181
|
+
current = curObj[key];
|
|
182
|
+
}
|
|
183
|
+
return current ?? default_;
|
|
184
|
+
}
|
|
185
|
+
function deepSet(obj, path, value) {
|
|
186
|
+
const keys = path.split(".");
|
|
187
|
+
const result = { ...obj };
|
|
188
|
+
let current = result;
|
|
189
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
190
|
+
const key = keys[i];
|
|
191
|
+
const next = current[key];
|
|
192
|
+
if (next === null || next === void 0 || typeof next !== "object") {
|
|
193
|
+
const isArray = /^\d+$/.test(keys[i + 1]);
|
|
194
|
+
current[key] = isArray ? [] : {};
|
|
195
|
+
}
|
|
196
|
+
current = current[key];
|
|
197
|
+
}
|
|
198
|
+
current[keys[keys.length - 1]] = value;
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
173
201
|
export {
|
|
174
202
|
chunk,
|
|
203
|
+
deepGet,
|
|
204
|
+
deepSet,
|
|
175
205
|
first,
|
|
176
206
|
flatten,
|
|
177
207
|
groupBy,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/collection/index.ts"],"sourcesContent":["/**\r\n * Groups an array of items by a key extracted from each item.\r\n *\r\n * @example groupBy([{ type: 'a' }, { type: 'b' }, { type: 'a' }], x => x.type)\r\n * // => { a: [{ type: 'a' }, { type: 'a' }], b: [{ type: 'b' }] }\r\n */\r\nexport function groupBy<T, K extends string | number | symbol>(items: T[], keyFn: (item: T) => K): Record<K, T[]> {\r\n const result = {} as Record<K, T[]>\r\n for (const item of items) {\r\n const key = keyFn(item)\r\n if (!result[key]) result[key] = []\r\n result[key]!.push(item)\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Creates an object keyed by the result of keyFn for each item.\r\n *\r\n * @example keyBy([{ id: 1, name: 'a' }, { id: 2, name: 'b' }], x => x.id)\r\n * // => { 1: { id: 1, name: 'a' }, 2: { id: 2, name: 'b' } }\r\n */\r\nexport function keyBy<T, K extends string | number | symbol>(items: T[], keyFn: (item: T) => K): Record<K, T> {\r\n const result = {} as Record<K, T>\r\n for (const item of items) {\r\n const key = keyFn(item)\r\n result[key] = item\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Returns a copy of the object with the specified keys omitted.\r\n */\r\nexport function omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {\r\n const result = { ...obj } as T\r\n for (const key of keys) {\r\n delete result[key]\r\n }\r\n return result as Omit<T, K>\r\n}\r\n\r\n/**\r\n * Returns a copy of the object with only the specified keys.\r\n */\r\nexport function pick<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {\r\n const result = {} as Pick<T, K>\r\n for (const key of keys) {\r\n if (key in obj) {\r\n result[key] = obj[key]\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Extracts a property value from each item in an array.\r\n */\r\nexport function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] {\r\n return items.map(item => item[key])\r\n}\r\n\r\n/**\r\n * Randomizes array order in-place using the Fisher-Yates algorithm.\r\n */\r\nexport function shuffle<T>(items: T[]): T[] {\r\n const result = [...items]\r\n for (let i = result.length - 1; i > 0; i--) {\r\n const j = Math.floor(Math.random() * (i + 1))\r\n const temp = result[i]!\r\n result[i] = result[j]!\r\n result[j] = temp\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Returns a random element from the array, or undefined if empty.\r\n */\r\nexport function sample<T>(items: T[]): T | undefined {\r\n return items.length > 0 ? items[Math.floor(Math.random() * items.length)] : undefined\r\n}\r\n\r\n/**\r\n * Returns an array of `size` random elements (without duplicates).\r\n */\r\nexport function sampleSize<T>(items: T[], size: number): T[] {\r\n if (size <= 0 || items.length === 0) return []\r\n const pool = shuffle(items)\r\n return pool.slice(0, Math.min(size, items.length))\r\n}\r\n\r\n/**\r\n * Splits an array into chunks of the specified size.\r\n */\r\nexport function chunk<T>(items: T[], size: number): T[][] {\r\n if (size <= 0 || items.length === 0) return []\r\n const result: T[][] = []\r\n for (let i = 0; i < items.length; i += size) {\r\n result.push(items.slice(i, i + size))\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Returns a sorted copy of the array using the provided criteria functions.\r\n * Earlier criteria take precedence.\r\n */\r\nfunction compareValues(a: unknown, b: unknown): number {\r\n if (a === b) return 0\r\n if (a == null) return -1\r\n if (b == null) return 1\r\n if (typeof a === 'string' && typeof b === 'string') return a < b ? -1 : 1\r\n if (typeof a === 'number' && typeof b === 'number') return a < b ? -1 : 1\r\n return String(a) < String(b) ? -1 : 1\r\n}\r\n\r\nexport function sortBy<T>(items: T[], ...criteria: Array<(item: T) => unknown>): T[] {\r\n return [...items].sort((a, b) => {\r\n for (const criterion of criteria) {\r\n const cmp = compareValues(criterion(a), criterion(b))\r\n if (cmp !== 0) return cmp\r\n }\r\n return 0\r\n })\r\n}\r\n\r\n/**\r\n * Returns a sorted copy of the array by a single key and direction.\r\n */\r\nexport function orderBy<T>(items: T[], key: (item: T) => unknown, direction: SortDirection = 'asc'): T[] {\r\n return [...items].sort((a, b) => {\r\n const cmp = compareValues(key(a), key(b))\r\n return direction === 'asc' ? cmp : -cmp\r\n })\r\n}\r\n\r\n/**\r\n * Returns unique elements based on the result of keyFn.\r\n */\r\nexport function uniqueBy<T>(items: T[], keyFn: (item: T) => unknown): T[] {\r\n const seen = new Set<unknown>()\r\n return items.filter(item => {\r\n const key = keyFn(item)\r\n if (seen.has(key)) return false\r\n seen.add(key)\r\n return true\r\n })\r\n}\r\n\r\n/**\r\n * Flattens an array of arrays one level.\r\n */\r\nexport function flatten<T>(items: T[][]): T[] {\r\n const result: T[] = []\r\n for (const sub of items) {\r\n for (const item of sub) {\r\n result.push(item)\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Returns an array with unique primitive values.\r\n */\r\nexport function uniq<T>(items: T[]): T[] {\r\n return [...new Set(items)]\r\n}\r\n\r\n/**\r\n * Returns the first element, or undefined if empty.\r\n */\r\nexport function first<T>(items: T[]): T | undefined {\r\n return items[0]\r\n}\r\n\r\n/**\r\n * Returns the last element, or undefined if empty.\r\n */\r\nexport function last<T>(items: T[]): T | undefined {\r\n return items[items.length - 1]\r\n}\r\n\r\n/**\r\n * Checks if a value is empty.\r\n * Works for arrays, objects, strings, Map, and Set.\r\n */\r\nexport function isEmpty(value: unknown): boolean {\r\n if (Array.isArray(value)) return value.length === 0\r\n if (typeof value === 'string') return value.length === 0\r\n if (value instanceof Map || value instanceof Set) return value.size === 0\r\n if (value !== null && typeof value === 'object') return Object.keys(value as Record<string, unknown>).length === 0\r\n return false\r\n}\r\n\r\nexport type SortDirection = 'asc' | 'desc'\r\n\r\nexport function topoSort<T extends { id: string; dependencies?: string[] }>(items: T[]): T[] {\r\n const adj = new Map<string, string[]>()\r\n const inDegree = new Map<string, number>()\r\n const itemMap = new Map<string, T>()\r\n\r\n for (const item of items) {\r\n itemMap.set(item.id, item)\r\n if (!adj.has(item.id)) adj.set(item.id, [])\r\n if (!inDegree.has(item.id)) inDegree.set(item.id, 0)\r\n }\r\n\r\n for (const item of items) {\r\n if (item.dependencies) {\r\n for (const depId of item.dependencies) {\r\n adj.get(depId)?.push(item.id)\r\n inDegree.set(item.id, (inDegree.get(item.id) ?? 0) + 1)\r\n }\r\n }\r\n }\r\n\r\n const queue: string[] = []\r\n for (const [id, degree] of inDegree) {\r\n if (degree === 0) queue.push(id)\r\n }\r\n\r\n const sorted: string[] = []\r\n while (queue.length > 0) {\r\n const id = queue.shift()!\r\n sorted.push(id)\r\n for (const neighbor of adj.get(id) ?? []) {\r\n const newDegree = (inDegree.get(neighbor) ?? 1) - 1\r\n inDegree.set(neighbor, newDegree)\r\n if (newDegree === 0) queue.push(neighbor)\r\n }\r\n }\r\n\r\n if (sorted.length !== items.length) {\r\n throw new Error('Circular dependency detected')\r\n }\r\n\r\n return sorted.map(id => itemMap.get(id)!)\r\n}\r\n\r\nexport function slidingWindows<T>(items: T[], size: number, step: number = 1): T[][] {\r\n if (size <= 0 || items.length === 0 || step <= 0) return []\r\n const result: T[][] = []\r\n for (let i = 0; i + size <= items.length; i += step) {\r\n result.push(items.slice(i, i + size))\r\n }\r\n return result\r\n}\r\n\r\nexport function tumblingWindows<T>(items: T[], size: number): T[][] {\r\n if (size <= 0 || items.length === 0) return []\r\n const result: T[][] = []\r\n for (let i = 0; i < items.length; i += size) {\r\n result.push(items.slice(i, i + size))\r\n }\r\n return result\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/collection/index.ts"],"sourcesContent":["/**\r\n * Groups an array of items by a key extracted from each item.\r\n *\r\n * @example groupBy([{ type: 'a' }, { type: 'b' }, { type: 'a' }], x => x.type)\r\n * // => { a: [{ type: 'a' }, { type: 'a' }], b: [{ type: 'b' }] }\r\n */\r\nexport function groupBy<T, K extends string | number | symbol>(items: T[], keyFn: (item: T) => K): Record<K, T[]> {\r\n const result = {} as Record<K, T[]>\r\n for (const item of items) {\r\n const key = keyFn(item)\r\n if (!result[key]) result[key] = []\r\n result[key]!.push(item)\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Creates an object keyed by the result of keyFn for each item.\r\n *\r\n * @example keyBy([{ id: 1, name: 'a' }, { id: 2, name: 'b' }], x => x.id)\r\n * // => { 1: { id: 1, name: 'a' }, 2: { id: 2, name: 'b' } }\r\n */\r\nexport function keyBy<T, K extends string | number | symbol>(items: T[], keyFn: (item: T) => K): Record<K, T> {\r\n const result = {} as Record<K, T>\r\n for (const item of items) {\r\n const key = keyFn(item)\r\n result[key] = item\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Returns a copy of the object with the specified keys omitted.\r\n */\r\nexport function omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {\r\n const result = { ...obj } as T\r\n for (const key of keys) {\r\n delete result[key]\r\n }\r\n return result as Omit<T, K>\r\n}\r\n\r\n/**\r\n * Returns a copy of the object with only the specified keys.\r\n */\r\nexport function pick<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {\r\n const result = {} as Pick<T, K>\r\n for (const key of keys) {\r\n if (key in obj) {\r\n result[key] = obj[key]\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Extracts a property value from each item in an array.\r\n */\r\nexport function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] {\r\n return items.map(item => item[key])\r\n}\r\n\r\n/**\r\n * Randomizes array order in-place using the Fisher-Yates algorithm.\r\n */\r\nexport function shuffle<T>(items: T[]): T[] {\r\n const result = [...items]\r\n for (let i = result.length - 1; i > 0; i--) {\r\n const j = Math.floor(Math.random() * (i + 1))\r\n const temp = result[i]!\r\n result[i] = result[j]!\r\n result[j] = temp\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Returns a random element from the array, or undefined if empty.\r\n */\r\nexport function sample<T>(items: T[]): T | undefined {\r\n return items.length > 0 ? items[Math.floor(Math.random() * items.length)] : undefined\r\n}\r\n\r\n/**\r\n * Returns an array of `size` random elements (without duplicates).\r\n */\r\nexport function sampleSize<T>(items: T[], size: number): T[] {\r\n if (size <= 0 || items.length === 0) return []\r\n const pool = shuffle(items)\r\n return pool.slice(0, Math.min(size, items.length))\r\n}\r\n\r\n/**\r\n * Splits an array into chunks of the specified size.\r\n */\r\nexport function chunk<T>(items: T[], size: number): T[][] {\r\n if (size <= 0 || items.length === 0) return []\r\n const result: T[][] = []\r\n for (let i = 0; i < items.length; i += size) {\r\n result.push(items.slice(i, i + size))\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Returns a sorted copy of the array using the provided criteria functions.\r\n * Earlier criteria take precedence.\r\n */\r\nfunction compareValues(a: unknown, b: unknown): number {\r\n if (a === b) return 0\r\n if (a == null) return -1\r\n if (b == null) return 1\r\n if (typeof a === 'string' && typeof b === 'string') return a < b ? -1 : 1\r\n if (typeof a === 'number' && typeof b === 'number') return a < b ? -1 : 1\r\n return String(a) < String(b) ? -1 : 1\r\n}\r\n\r\nexport function sortBy<T>(items: T[], ...criteria: Array<(item: T) => unknown>): T[] {\r\n return [...items].sort((a, b) => {\r\n for (const criterion of criteria) {\r\n const cmp = compareValues(criterion(a), criterion(b))\r\n if (cmp !== 0) return cmp\r\n }\r\n return 0\r\n })\r\n}\r\n\r\n/**\r\n * Returns a sorted copy of the array by a single key and direction.\r\n */\r\nexport function orderBy<T>(items: T[], key: (item: T) => unknown, direction: SortDirection = 'asc'): T[] {\r\n return [...items].sort((a, b) => {\r\n const cmp = compareValues(key(a), key(b))\r\n return direction === 'asc' ? cmp : -cmp\r\n })\r\n}\r\n\r\n/**\r\n * Returns unique elements based on the result of keyFn.\r\n */\r\nexport function uniqueBy<T>(items: T[], keyFn: (item: T) => unknown): T[] {\r\n const seen = new Set<unknown>()\r\n return items.filter(item => {\r\n const key = keyFn(item)\r\n if (seen.has(key)) return false\r\n seen.add(key)\r\n return true\r\n })\r\n}\r\n\r\n/**\r\n * Flattens an array of arrays one level.\r\n */\r\nexport function flatten<T>(items: T[][]): T[] {\r\n const result: T[] = []\r\n for (const sub of items) {\r\n for (const item of sub) {\r\n result.push(item)\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Returns an array with unique primitive values.\r\n */\r\nexport function uniq<T>(items: T[]): T[] {\r\n return [...new Set(items)]\r\n}\r\n\r\n/**\r\n * Returns the first element, or undefined if empty.\r\n */\r\nexport function first<T>(items: T[]): T | undefined {\r\n return items[0]\r\n}\r\n\r\n/**\r\n * Returns the last element, or undefined if empty.\r\n */\r\nexport function last<T>(items: T[]): T | undefined {\r\n return items[items.length - 1]\r\n}\r\n\r\n/**\r\n * Checks if a value is empty.\r\n * Works for arrays, objects, strings, Map, and Set.\r\n */\r\nexport function isEmpty(value: unknown): boolean {\r\n if (Array.isArray(value)) return value.length === 0\r\n if (typeof value === 'string') return value.length === 0\r\n if (value instanceof Map || value instanceof Set) return value.size === 0\r\n if (value !== null && typeof value === 'object') return Object.keys(value as Record<string, unknown>).length === 0\r\n return false\r\n}\r\n\r\nexport type SortDirection = 'asc' | 'desc'\r\n\r\nexport function topoSort<T extends { id: string; dependencies?: string[] }>(items: T[]): T[] {\r\n const adj = new Map<string, string[]>()\r\n const inDegree = new Map<string, number>()\r\n const itemMap = new Map<string, T>()\r\n\r\n for (const item of items) {\r\n itemMap.set(item.id, item)\r\n if (!adj.has(item.id)) adj.set(item.id, [])\r\n if (!inDegree.has(item.id)) inDegree.set(item.id, 0)\r\n }\r\n\r\n for (const item of items) {\r\n if (item.dependencies) {\r\n for (const depId of item.dependencies) {\r\n adj.get(depId)?.push(item.id)\r\n inDegree.set(item.id, (inDegree.get(item.id) ?? 0) + 1)\r\n }\r\n }\r\n }\r\n\r\n const queue: string[] = []\r\n for (const [id, degree] of inDegree) {\r\n if (degree === 0) queue.push(id)\r\n }\r\n\r\n const sorted: string[] = []\r\n while (queue.length > 0) {\r\n const id = queue.shift()!\r\n sorted.push(id)\r\n for (const neighbor of adj.get(id) ?? []) {\r\n const newDegree = (inDegree.get(neighbor) ?? 1) - 1\r\n inDegree.set(neighbor, newDegree)\r\n if (newDegree === 0) queue.push(neighbor)\r\n }\r\n }\r\n\r\n if (sorted.length !== items.length) {\r\n throw new Error('Circular dependency detected')\r\n }\r\n\r\n return sorted.map(id => itemMap.get(id)!)\r\n}\r\n\r\nexport function slidingWindows<T>(items: T[], size: number, step: number = 1): T[][] {\r\n if (size <= 0 || items.length === 0 || step <= 0) return []\r\n const result: T[][] = []\r\n for (let i = 0; i + size <= items.length; i += step) {\r\n result.push(items.slice(i, i + size))\r\n }\r\n return result\r\n}\r\n\r\nexport function tumblingWindows<T>(items: T[], size: number): T[][] {\r\n if (size <= 0 || items.length === 0) return []\r\n const result: T[][] = []\r\n for (let i = 0; i < items.length; i += size) {\r\n result.push(items.slice(i, i + size))\r\n }\r\n return result\r\n}\r\n\r\n/**\r\n * Gets a nested value from an object using a dot-separated path.\r\n *\r\n * @example deepGet({ a: { b: 2 } }, 'a.b') // 2\r\n * @example deepGet({ a: { b: 2 } }, 'a.c') // undefined\r\n */\r\nexport function deepGet<T = unknown>(obj: unknown, path: string, default_?: T): T | undefined {\r\n const keys = path.split('.')\r\n let current: unknown = obj\r\n for (const key of keys) {\r\n if (current === null || current === undefined) return default_\r\n if (typeof current !== 'object') return default_\r\n const curObj = current as Record<string, unknown>\r\n if (!(key in curObj)) return default_\r\n current = curObj[key]\r\n }\r\n return (current as T) ?? default_\r\n}\r\n\r\n/**\r\n * Sets a nested value in an object using a dot-separated path.\r\n * Creates intermediate objects/arrays as needed.\r\n *\r\n * @example deepSet({ a: { b: 2 } }, 'a.b', 3) // { a: { b: 3 } }\r\n * @example deepSet({}, 'a.b.c', 1) // { a: { b: { c: 1 } } }\r\n */\r\nexport function deepSet<T extends Record<string, unknown>>(obj: T, path: string, value: unknown): T {\r\n const keys = path.split('.')\r\n const result = { ...obj } as Record<string, unknown>\r\n let current = result\r\n for (let i = 0; i < keys.length - 1; i++) {\r\n const key = keys[i]!\r\n const next = current[key]\r\n if (next === null || next === undefined || typeof next !== 'object') {\r\n const isArray = /^\\d+$/.test(keys[i + 1]!)\r\n current[key] = isArray ? [] : {}\r\n }\r\n current = current[key] as Record<string, unknown>\r\n }\r\n current[keys[keys.length - 1]!] = value\r\n return result as T\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a hex color string to RGB values.
|
|
3
|
+
*
|
|
4
|
+
* @example hexToRgb('#ff0000') // { r: 255, g: 0, b: 0 }
|
|
5
|
+
* @example hexToRgb('#f00') // { r: 255, g: 0, b: 0 }
|
|
6
|
+
* @example hexToRgb('#FF8800') // { r: 255, g: 136, b: 0 }
|
|
7
|
+
*/
|
|
8
|
+
declare function hexToRgb(hex: string): {
|
|
9
|
+
r: number;
|
|
10
|
+
g: number;
|
|
11
|
+
b: number;
|
|
12
|
+
} | null;
|
|
13
|
+
/**
|
|
14
|
+
* Converts RGB values to a hex color string.
|
|
15
|
+
*
|
|
16
|
+
* @example rgbToHex(255, 0, 0) // "#ff0000"
|
|
17
|
+
* @example rgbToHex(255, 136, 0) // "#ff8800"
|
|
18
|
+
*/
|
|
19
|
+
declare function rgbToHex(r: number, g: number, b: number): string;
|
|
20
|
+
/**
|
|
21
|
+
* Lightens a hex color by a given percentage (0-100).
|
|
22
|
+
*
|
|
23
|
+
* @example lighten('#ff0000', 20) // "#ff3333"
|
|
24
|
+
* @example lighten('#0000ff', 50) // "#7f7fff"
|
|
25
|
+
*/
|
|
26
|
+
declare function lighten(hex: string, percent: number): string;
|
|
27
|
+
/**
|
|
28
|
+
* Darkens a hex color by a given percentage (0-100).
|
|
29
|
+
*
|
|
30
|
+
* @example darken('#ff0000', 20) // "#cc0000"
|
|
31
|
+
* @example darken('#00ff00', 50) // "#008000"
|
|
32
|
+
*/
|
|
33
|
+
declare function darken(hex: string, percent: number): string;
|
|
34
|
+
/**
|
|
35
|
+
* Checks the WCAG contrast ratio between two hex colors.
|
|
36
|
+
* Returns the ratio as a number (1-21). WCAG AA requires 4.5:1 for normal text.
|
|
37
|
+
*
|
|
38
|
+
* @example contrastRatio('#000000', '#ffffff') // 21
|
|
39
|
+
* @example contrastRatio('#ff0000', '#ffffff') // 3.99
|
|
40
|
+
*/
|
|
41
|
+
declare function contrastRatio(hex1: string, hex2: string): number;
|
|
42
|
+
/**
|
|
43
|
+
* Checks if a hex color meets WCAG AA contrast ratio (4.5:1) against another color.
|
|
44
|
+
*
|
|
45
|
+
* @example meetsWCAG('#000000', '#ffffff') // true (black on white)
|
|
46
|
+
* @example meetsWCAG('#999999', '#ffffff') // false (gray on white)
|
|
47
|
+
*/
|
|
48
|
+
declare function meetsWCAG(hex1: string, hex2: string, level?: 'AA' | 'AAA'): boolean;
|
|
49
|
+
|
|
50
|
+
export { contrastRatio, darken, hexToRgb, lighten, meetsWCAG, rgbToHex };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// src/color/index.ts
|
|
2
|
+
function hexToRgb(hex) {
|
|
3
|
+
let h = hex.replace("#", "");
|
|
4
|
+
if (h.length === 3) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
|
|
5
|
+
if (h.length !== 6) return null;
|
|
6
|
+
const num = Number.parseInt(h, 16);
|
|
7
|
+
if (isNaN(num)) return null;
|
|
8
|
+
return {
|
|
9
|
+
r: num >> 16 & 255,
|
|
10
|
+
g: num >> 8 & 255,
|
|
11
|
+
b: num & 255
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function rgbToHex(r, g, b) {
|
|
15
|
+
const toHex = (n) => Math.max(0, Math.min(255, Math.round(n))).toString(16).padStart(2, "0");
|
|
16
|
+
return "#" + toHex(r) + toHex(g) + toHex(b);
|
|
17
|
+
}
|
|
18
|
+
function lighten(hex, percent) {
|
|
19
|
+
const rgb = hexToRgb(hex);
|
|
20
|
+
if (!rgb) return hex;
|
|
21
|
+
const factor = percent / 100;
|
|
22
|
+
return rgbToHex(
|
|
23
|
+
rgb.r + (255 - rgb.r) * factor,
|
|
24
|
+
rgb.g + (255 - rgb.g) * factor,
|
|
25
|
+
rgb.b + (255 - rgb.b) * factor
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
function darken(hex, percent) {
|
|
29
|
+
const rgb = hexToRgb(hex);
|
|
30
|
+
if (!rgb) return hex;
|
|
31
|
+
const factor = percent / 100;
|
|
32
|
+
return rgbToHex(
|
|
33
|
+
rgb.r * (1 - factor),
|
|
34
|
+
rgb.g * (1 - factor),
|
|
35
|
+
rgb.b * (1 - factor)
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
function contrastRatio(hex1, hex2) {
|
|
39
|
+
const lum1 = relativeLuminance(hex1);
|
|
40
|
+
const lum2 = relativeLuminance(hex2);
|
|
41
|
+
const lighter = Math.max(lum1, lum2);
|
|
42
|
+
const darker = Math.min(lum1, lum2);
|
|
43
|
+
return Number(((lighter + 0.05) / (darker + 0.05)).toFixed(2));
|
|
44
|
+
}
|
|
45
|
+
function relativeLuminance(hex) {
|
|
46
|
+
const rgb = hexToRgb(hex);
|
|
47
|
+
if (!rgb) return 0;
|
|
48
|
+
const vals = [rgb.r / 255, rgb.g / 255, rgb.b / 255].map((c) => {
|
|
49
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
50
|
+
});
|
|
51
|
+
return 0.2126 * vals[0] + 0.7152 * vals[1] + 0.0722 * vals[2];
|
|
52
|
+
}
|
|
53
|
+
function meetsWCAG(hex1, hex2, level) {
|
|
54
|
+
const ratio = contrastRatio(hex1, hex2);
|
|
55
|
+
const threshold = level === "AAA" ? 7 : 4.5;
|
|
56
|
+
return ratio >= threshold;
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
contrastRatio,
|
|
60
|
+
darken,
|
|
61
|
+
hexToRgb,
|
|
62
|
+
lighten,
|
|
63
|
+
meetsWCAG,
|
|
64
|
+
rgbToHex
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/color/index.ts"],"sourcesContent":["/**\n * Converts a hex color string to RGB values.\n *\n * @example hexToRgb('#ff0000') // { r: 255, g: 0, b: 0 }\n * @example hexToRgb('#f00') // { r: 255, g: 0, b: 0 }\n * @example hexToRgb('#FF8800') // { r: 255, g: 136, b: 0 }\n */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n let h = hex.replace('#', '')\n if (h.length === 3) h = h[0]! + h[0] + h[1]! + h[1] + h[2]! + h[2]\n if (h.length !== 6) return null\n const num = Number.parseInt(h, 16)\n if (isNaN(num)) return null\n return {\n r: (num >> 16) & 255,\n g: (num >> 8) & 255,\n b: num & 255,\n }\n}\n\n/**\n * Converts RGB values to a hex color string.\n *\n * @example rgbToHex(255, 0, 0) // \"#ff0000\"\n * @example rgbToHex(255, 136, 0) // \"#ff8800\"\n */\nexport function rgbToHex(r: number, g: number, b: number): string {\n const toHex = (n: number) => Math.max(0, Math.min(255, Math.round(n))).toString(16).padStart(2, '0')\n return '#' + toHex(r) + toHex(g) + toHex(b)\n}\n\n/**\n * Lightens a hex color by a given percentage (0-100).\n *\n * @example lighten('#ff0000', 20) // \"#ff3333\"\n * @example lighten('#0000ff', 50) // \"#7f7fff\"\n */\nexport function lighten(hex: string, percent: number): string {\n const rgb = hexToRgb(hex)\n if (!rgb) return hex\n const factor = percent / 100\n return rgbToHex(\n rgb.r + (255 - rgb.r) * factor,\n rgb.g + (255 - rgb.g) * factor,\n rgb.b + (255 - rgb.b) * factor,\n )\n}\n\n/**\n * Darkens a hex color by a given percentage (0-100).\n *\n * @example darken('#ff0000', 20) // \"#cc0000\"\n * @example darken('#00ff00', 50) // \"#008000\"\n */\nexport function darken(hex: string, percent: number): string {\n const rgb = hexToRgb(hex)\n if (!rgb) return hex\n const factor = percent / 100\n return rgbToHex(\n rgb.r * (1 - factor),\n rgb.g * (1 - factor),\n rgb.b * (1 - factor),\n )\n}\n\n/**\n * Checks the WCAG contrast ratio between two hex colors.\n * Returns the ratio as a number (1-21). WCAG AA requires 4.5:1 for normal text.\n *\n * @example contrastRatio('#000000', '#ffffff') // 21\n * @example contrastRatio('#ff0000', '#ffffff') // 3.99\n */\nexport function contrastRatio(hex1: string, hex2: string): number {\n const lum1 = relativeLuminance(hex1)\n const lum2 = relativeLuminance(hex2)\n const lighter = Math.max(lum1, lum2)\n const darker = Math.min(lum1, lum2)\n return Number(((lighter + 0.05) / (darker + 0.05)).toFixed(2))\n}\n\nfunction relativeLuminance(hex: string): number {\n const rgb = hexToRgb(hex)\n if (!rgb) return 0\n const vals = [rgb.r / 255, rgb.g / 255, rgb.b / 255].map((c) => {\n return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)\n })\n return 0.2126 * vals[0]! + 0.7152 * vals[1]! + 0.0722 * vals[2]!\n}\n\n/**\n * Checks if a hex color meets WCAG AA contrast ratio (4.5:1) against another color.\n *\n * @example meetsWCAG('#000000', '#ffffff') // true (black on white)\n * @example meetsWCAG('#999999', '#ffffff') // false (gray on white)\n */\nexport function meetsWCAG(hex1: string, hex2: string, level?: 'AA' | 'AAA'): boolean {\n const ratio = contrastRatio(hex1, hex2)\n const threshold = level === 'AAA' ? 7 : 4.5\n return ratio >= threshold\n}\n"],"mappings":";AAOO,SAAS,SAAS,KAAyD;AAChF,MAAI,IAAI,IAAI,QAAQ,KAAK,EAAE;AAC3B,MAAI,EAAE,WAAW,EAAG,KAAI,EAAE,CAAC,IAAK,EAAE,CAAC,IAAI,EAAE,CAAC,IAAK,EAAE,CAAC,IAAI,EAAE,CAAC,IAAK,EAAE,CAAC;AACjE,MAAI,EAAE,WAAW,EAAG,QAAO;AAC3B,QAAM,MAAM,OAAO,SAAS,GAAG,EAAE;AACjC,MAAI,MAAM,GAAG,EAAG,QAAO;AACvB,SAAO;AAAA,IACL,GAAI,OAAO,KAAM;AAAA,IACjB,GAAI,OAAO,IAAK;AAAA,IAChB,GAAG,MAAM;AAAA,EACX;AACF;AAQO,SAAS,SAAS,GAAW,GAAW,GAAmB;AAChE,QAAM,QAAQ,CAAC,MAAc,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACnG,SAAO,MAAM,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,CAAC;AAC5C;AAQO,SAAS,QAAQ,KAAa,SAAyB;AAC5D,QAAM,MAAM,SAAS,GAAG;AACxB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,SAAS,UAAU;AACzB,SAAO;AAAA,IACL,IAAI,KAAK,MAAM,IAAI,KAAK;AAAA,IACxB,IAAI,KAAK,MAAM,IAAI,KAAK;AAAA,IACxB,IAAI,KAAK,MAAM,IAAI,KAAK;AAAA,EAC1B;AACF;AAQO,SAAS,OAAO,KAAa,SAAyB;AAC3D,QAAM,MAAM,SAAS,GAAG;AACxB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,SAAS,UAAU;AACzB,SAAO;AAAA,IACL,IAAI,KAAK,IAAI;AAAA,IACb,IAAI,KAAK,IAAI;AAAA,IACb,IAAI,KAAK,IAAI;AAAA,EACf;AACF;AASO,SAAS,cAAc,MAAc,MAAsB;AAChE,QAAM,OAAO,kBAAkB,IAAI;AACnC,QAAM,OAAO,kBAAkB,IAAI;AACnC,QAAM,UAAU,KAAK,IAAI,MAAM,IAAI;AACnC,QAAM,SAAS,KAAK,IAAI,MAAM,IAAI;AAClC,SAAO,SAAS,UAAU,SAAS,SAAS,OAAO,QAAQ,CAAC,CAAC;AAC/D;AAEA,SAAS,kBAAkB,KAAqB;AAC9C,QAAM,MAAM,SAAS,GAAG;AACxB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,OAAO,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,EAAE,IAAI,CAAC,MAAM;AAC9D,WAAO,KAAK,UAAU,IAAI,QAAQ,KAAK,KAAK,IAAI,SAAS,OAAO,GAAG;AAAA,EACrE,CAAC;AACD,SAAO,SAAS,KAAK,CAAC,IAAK,SAAS,KAAK,CAAC,IAAK,SAAS,KAAK,CAAC;AAChE;AAQO,SAAS,UAAU,MAAc,MAAc,OAA+B;AACnF,QAAM,QAAQ,cAAc,MAAM,IAAI;AACtC,QAAM,YAAY,UAAU,QAAQ,IAAI;AACxC,SAAO,SAAS;AAClB;","names":[]}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -91,5 +91,29 @@ declare function identity<T>(value: T): T;
|
|
|
91
91
|
* @returns A function that runs only once.
|
|
92
92
|
*/
|
|
93
93
|
declare function once<T extends (...args: unknown[]) => unknown>(fn: T): (...args: Parameters<T>) => ReturnType<T>;
|
|
94
|
+
/**
|
|
95
|
+
* Deep equality check between two values. Supports primitives, objects,
|
|
96
|
+
* arrays, Date, RegExp, Map, Set, and nested structures. Circular
|
|
97
|
+
* references are handled.
|
|
98
|
+
*
|
|
99
|
+
* @example deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } }) // true
|
|
100
|
+
* @example deepEqual({ a: 1 }, { a: 2 }) // false
|
|
101
|
+
*/
|
|
102
|
+
declare function deepEqual(a: unknown, b: unknown): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Performs left-to-right function composition.
|
|
105
|
+
*
|
|
106
|
+
* @example const fn = pipe((x: number) => x + 1, (x: number) => x * 2)
|
|
107
|
+
* fn(3) // 8
|
|
108
|
+
*/
|
|
109
|
+
declare function pipe<T>(initial: T, ...fns: Array<(arg: T) => T>): T;
|
|
110
|
+
declare function pipe<T, R>(initial: T, ...fns: Array<(arg: unknown) => unknown>): R;
|
|
111
|
+
/**
|
|
112
|
+
* Performs right-to-left function composition.
|
|
113
|
+
*
|
|
114
|
+
* @example const fn = compose((x: number) => x * 2, (x: number) => x + 1)
|
|
115
|
+
* fn(3) // 8 — same as (3+1)*2
|
|
116
|
+
*/
|
|
117
|
+
declare function compose<T>(...fns: Array<(arg: T) => T>): (initial: T) => T;
|
|
94
118
|
|
|
95
|
-
export { type DebounceOptions, type DebouncedFunction, type MemoizedFunction, type RetryOptions, debounce, deepClone, deepMerge, identity, memoize, noop, once, retry, throttle };
|
|
119
|
+
export { type DebounceOptions, type DebouncedFunction, type MemoizedFunction, type RetryOptions, compose, debounce, deepClone, deepEqual, deepMerge, identity, memoize, noop, once, pipe, retry, throttle };
|
package/dist/core/index.js
CHANGED
|
@@ -258,14 +258,65 @@ function once(fn) {
|
|
|
258
258
|
return result;
|
|
259
259
|
};
|
|
260
260
|
}
|
|
261
|
+
function deepEqual(a, b) {
|
|
262
|
+
if (Object.is(a, b)) return true;
|
|
263
|
+
if (a === null || b === null || typeof a !== typeof b) return false;
|
|
264
|
+
if (typeof a !== "object") return false;
|
|
265
|
+
const aObj = a;
|
|
266
|
+
const bObj = b;
|
|
267
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
268
|
+
if (a.length !== b.length) return false;
|
|
269
|
+
for (let i = 0; i < a.length; i++) {
|
|
270
|
+
if (!deepEqual(a[i], b[i])) return false;
|
|
271
|
+
}
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
if (a instanceof Date && b instanceof Date) {
|
|
275
|
+
return a.getTime() === b.getTime();
|
|
276
|
+
}
|
|
277
|
+
if (a instanceof RegExp && b instanceof RegExp) {
|
|
278
|
+
return a.source === b.source && a.flags === b.flags;
|
|
279
|
+
}
|
|
280
|
+
if (a instanceof Map && b instanceof Map) {
|
|
281
|
+
if (a.size !== b.size) return false;
|
|
282
|
+
for (const [k, v] of a) {
|
|
283
|
+
if (!b.has(k) || !deepEqual(v, b.get(k))) return false;
|
|
284
|
+
}
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
if (a instanceof Set && b instanceof Set) {
|
|
288
|
+
if (a.size !== b.size) return false;
|
|
289
|
+
for (const v of a) {
|
|
290
|
+
if (!b.has(v)) return false;
|
|
291
|
+
}
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
const keysA = Object.keys(aObj);
|
|
295
|
+
const keysB = Object.keys(bObj);
|
|
296
|
+
if (keysA.length !== keysB.length) return false;
|
|
297
|
+
for (const key of keysA) {
|
|
298
|
+
if (!Object.prototype.hasOwnProperty.call(bObj, key)) return false;
|
|
299
|
+
if (!deepEqual(aObj[key], bObj[key])) return false;
|
|
300
|
+
}
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
function pipe(initial, ...fns) {
|
|
304
|
+
return fns.reduce((acc, fn) => fn(acc), initial);
|
|
305
|
+
}
|
|
306
|
+
function compose(...fns) {
|
|
307
|
+
return (initial) => fns.reduceRight((acc, fn) => fn(acc), initial);
|
|
308
|
+
}
|
|
261
309
|
export {
|
|
310
|
+
compose,
|
|
262
311
|
debounce,
|
|
263
312
|
deepClone,
|
|
313
|
+
deepEqual,
|
|
264
314
|
deepMerge,
|
|
265
315
|
identity,
|
|
266
316
|
memoize,
|
|
267
317
|
noop,
|
|
268
318
|
once,
|
|
319
|
+
pipe,
|
|
269
320
|
retry,
|
|
270
321
|
throttle
|
|
271
322
|
};
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export interface DebounceOptions {\r\n leading?: boolean\r\n trailing?: boolean\r\n maxWait?: number\r\n}\r\n\r\nexport interface DebouncedFunction<T extends (...args: unknown[]) => unknown> {\r\n (...args: Parameters<T>): void\r\n cancel(): void\r\n flush(): void\r\n}\r\n\r\nexport interface MemoizedFunction<T extends (...args: unknown[]) => unknown> {\r\n (...args: Parameters<T>): ReturnType<T>\r\n cache: Map<string, ReturnType<T>>\r\n}\r\n\r\nexport interface RetryOptions {\r\n attempts?: number\r\n baseDelay?: number\r\n maxDelay?: number\r\n shouldRetry?: (error: unknown) => boolean\r\n}\r\n\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\r\n if (value === null || typeof value !== 'object') return false\r\n const proto = Object.getPrototypeOf(value)\r\n return proto === Object.prototype || proto === null\r\n}\r\n\r\nfunction getType(value: unknown): string {\r\n return Object.prototype.toString.call(value)\r\n}\r\n\r\nfunction clone<T>(value: T, seen: WeakMap<object, unknown>): T {\r\n if (value === null || typeof value !== 'object') return value\r\n\r\n if (seen.has(value as object)) return seen.get(value as object) as T\r\n\r\n const tag = getType(value)\r\n\r\n if (tag === '[object Date]') {\r\n const cloned = new Date((value as unknown as Date).getTime())\r\n seen.set(value as object, cloned)\r\n return cloned as unknown as T\r\n }\r\n\r\n if (tag === '[object RegExp]') {\r\n const regExp = value as unknown as RegExp\r\n const cloned = new RegExp(regExp.source, regExp.flags)\r\n cloned.lastIndex = regExp.lastIndex\r\n seen.set(value as object, cloned)\r\n return cloned as unknown as T\r\n }\r\n\r\n if (tag === '[object Map]') {\r\n const cloned = new Map<unknown, unknown>()\r\n seen.set(value as object, cloned)\r\n ;(value as unknown as Map<unknown, unknown>).forEach((v, k) => {\r\n cloned.set(clone(k, seen), clone(v, seen))\r\n })\r\n return cloned as unknown as T\r\n }\r\n\r\n if (tag === '[object Set]') {\r\n const cloned = new Set<unknown>()\r\n seen.set(value as object, cloned)\r\n ;(value as unknown as Set<unknown>).forEach(v => {\r\n cloned.add(clone(v, seen))\r\n })\r\n return cloned as unknown as T\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n const cloned: unknown[] = []\r\n seen.set(value as object, cloned)\r\n for (let i = 0; i < value.length; i++) {\r\n cloned[i] = clone(value[i], seen)\r\n }\r\n return cloned as unknown as T\r\n }\r\n\r\n if (tag === '[object Object]') {\r\n const cloned: Record<string, unknown> = {}\r\n seen.set(value as object, cloned)\r\n const keys = Object.keys(value as Record<string, unknown>)\r\n for (let i = 0; i < keys.length; i++) {\r\n const key = keys[i]!\r\n cloned[key] = clone((value as Record<string, unknown>)[key], seen)\r\n }\r\n return cloned as unknown as T\r\n }\r\n\r\n return value\r\n}\r\n\r\n/**\r\n * Deep clone a value, supporting objects, arrays, Date, RegExp, Map, Set,\r\n * and cyclic references.\r\n *\r\n * @param value - The value to clone.\r\n * @returns A deep copy of the input value.\r\n */\r\nexport function deepClone<T>(value: T): T {\r\n const seen = new WeakMap<object, unknown>()\r\n return clone(value, seen)\r\n}\r\n\r\n/**\r\n * Deep merge multiple objects. Arrays are overwritten, not concatenated.\r\n * `null` and `undefined` source objects are skipped.\r\n *\r\n * @param objects - The objects to merge.\r\n * @returns A new object with merged properties.\r\n */\r\nexport function deepMerge<T extends Record<string, unknown>>(...objects: Partial<T>[]): T {\r\n const result = {} as T\r\n\r\n for (let i = 0; i < objects.length; i++) {\r\n const obj = objects[i]\r\n if (obj === null || obj === undefined) continue\r\n\r\n const keys = Object.keys(obj) as (keyof T)[]\r\n for (let j = 0; j < keys.length; j++) {\r\n const key = keys[j]!\r\n const val = obj[key]\r\n const existing = result[key]\r\n\r\n if (val !== undefined && isPlainObject(val) && isPlainObject(existing)) {\r\n result[key] = deepMerge(\r\n existing as Record<string, unknown>,\r\n val as Record<string, unknown>\r\n ) as T[keyof T]\r\n } else if (val !== undefined) {\r\n result[key] = val as T[keyof T]\r\n }\r\n }\r\n }\r\n\r\n return result\r\n}\r\n\r\n/**\r\n * Creates a debounced function that delays invoking `fn` until after `wait`\r\n * milliseconds have elapsed since the last invocation. Supports leading,\r\n * trailing, and maxWait options. The returned function also has `.cancel()`\r\n * and `.flush()` methods.\r\n *\r\n * @param fn - The function to debounce.\r\n * @param wait - The number of milliseconds to delay.\r\n * @param options - Optional configuration.\r\n * @returns A debounced function with `.cancel()` and `.flush()`.\r\n */\r\nexport function debounce<T extends (...args: unknown[]) => unknown>(\r\n fn: T,\r\n wait: number,\r\n options?: DebounceOptions\r\n): DebouncedFunction<T> {\r\n const { leading = false, trailing = true, maxWait } = options ?? {}\r\n\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n let maxTimer: ReturnType<typeof setTimeout> | null = null\r\n let lastArgs: Parameters<T> | null = null\r\n let lastCallTime: number | null = null\r\n let lastInvokeTime = 0\r\n\r\n function invoke(time: number): void {\r\n lastInvokeTime = time\r\n if (lastArgs) {\r\n fn(...lastArgs)\r\n lastArgs = null\r\n }\r\n }\r\n\r\n function startTimer(waitTime: number): void {\r\n if (timer) clearTimeout(timer)\r\n timer = setTimeout(() => {\r\n const now = Date.now()\r\n if (lastArgs && trailing) {\r\n invoke(now)\r\n }\r\n timer = null\r\n lastCallTime = null\r\n }, waitTime)\r\n }\r\n\r\n function startMaxTimer(): void {\r\n if (maxWait === undefined || maxTimer) return\r\n maxTimer = setTimeout(() => {\r\n if (lastArgs) {\r\n invoke(Date.now())\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n lastCallTime = null\r\n }\r\n }, maxWait)\r\n }\r\n\r\n function clearAllTimers(): void {\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n if (maxTimer) {\r\n clearTimeout(maxTimer)\r\n maxTimer = null\r\n }\r\n }\r\n\r\n function shouldInvoke(time: number): boolean {\r\n if (lastCallTime === null) return true\r\n const timeSinceLastCall = time - lastCallTime\r\n const timeSinceLastInvoke = time - lastInvokeTime\r\n return (\r\n timeSinceLastCall >= wait ||\r\n (maxWait !== undefined && timeSinceLastInvoke >= maxWait)\r\n )\r\n }\r\n\r\n const debounced = function (this: unknown, ...args: Parameters<T>): void {\r\n const time = Date.now()\r\n const isInvoking = shouldInvoke(time)\r\n\r\n lastArgs = args\r\n lastCallTime = time\r\n\r\n if (isInvoking && !timer && leading) {\r\n invoke(time)\r\n }\r\n\r\n if (!timer) {\r\n startTimer(wait)\r\n if (maxWait !== undefined) {\r\n startMaxTimer()\r\n }\r\n }\r\n } as DebouncedFunction<T>\r\n\r\n debounced.cancel = (): void => {\r\n clearAllTimers()\r\n lastArgs = null\r\n lastCallTime = null\r\n lastInvokeTime = 0\r\n }\r\n\r\n debounced.flush = (): void => {\r\n if (timer && lastArgs) {\r\n invoke(Date.now())\r\n clearAllTimers()\r\n lastCallTime = null\r\n }\r\n }\r\n\r\n return debounced\r\n}\r\n\r\n/**\r\n * Creates a throttled function that only invokes `fn` at most once per\r\n * `wait` milliseconds.\r\n *\r\n * @param fn - The function to throttle.\r\n * @param wait - The number of milliseconds to throttle invocations to.\r\n * @returns A throttled function.\r\n */\r\nexport function throttle<T extends (...args: unknown[]) => unknown>(\r\n fn: T,\r\n wait: number\r\n): (...args: Parameters<T>) => void {\r\n let lastTime = 0\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n let lastArgs: Parameters<T> | null = null\r\n\r\n const throttled = function (this: unknown, ...args: Parameters<T>): void {\r\n const now = Date.now()\r\n const remaining = wait - (now - lastTime)\r\n\r\n if (remaining <= 0) {\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n lastTime = now\r\n lastArgs = null\r\n fn.apply(this, args)\r\n } else {\r\n lastArgs = args\r\n if (!timer) {\r\n timer = setTimeout(() => {\r\n lastTime = Date.now()\r\n timer = null\r\n if (lastArgs) {\r\n fn.apply(this, lastArgs)\r\n lastArgs = null\r\n }\r\n }, remaining)\r\n }\r\n }\r\n }\r\n\r\n return throttled\r\n}\r\n\r\n/**\r\n * Creates a memoized version of `fn`. Uses a `Map` cache keyed by the\r\n * first argument by default, or by a custom `resolver` function.\r\n *\r\n * @param fn - The function to memoize.\r\n * @param resolver - Optional function to determine the cache key.\r\n * @returns The memoized function with a `.cache` property.\r\n */\r\nexport function memoize<T extends (...args: unknown[]) => unknown>(\r\n fn: T,\r\n resolver?: (...args: Parameters<T>) => string\r\n): MemoizedFunction<T> {\r\n const cache = new Map<string, ReturnType<T>>()\r\n\r\n const memoized = function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\r\n const key = resolver ? resolver(...args) : String(args[0])\r\n if (cache.has(key)) {\r\n return cache.get(key) as ReturnType<T>\r\n }\r\n const result = fn.apply(this, args) as ReturnType<T>\r\n cache.set(key, result)\r\n return result\r\n }\r\n\r\n memoized.cache = cache\r\n\r\n return memoized as MemoizedFunction<T>\r\n}\r\n\r\n/**\r\n * Retries an async function with exponential backoff and jitter.\r\n *\r\n * @param fn - The async function to retry.\r\n * @param options - Retry configuration.\r\n * @returns A promise that resolves with the function result.\r\n */\r\nexport function retry<T>(\r\n fn: () => Promise<T>,\r\n options?: RetryOptions\r\n): Promise<T> {\r\n const {\r\n attempts = 3,\r\n baseDelay = 1000,\r\n maxDelay = 30000,\r\n shouldRetry = () => true,\r\n } = options ?? {}\r\n\r\n let attempt = 0\r\n\r\n const execute = (): Promise<T> => {\r\n attempt++\r\n return fn().catch((error: unknown) => {\r\n if (attempt >= attempts || !shouldRetry(error)) {\r\n throw error\r\n }\r\n\r\n const delay = Math.min(\r\n baseDelay * Math.pow(2, attempt - 1) + Math.random() * baseDelay,\r\n maxDelay\r\n )\r\n\r\n return new Promise<T>(resolve => {\r\n setTimeout(() => {\r\n resolve(execute())\r\n }, delay)\r\n })\r\n })\r\n }\r\n\r\n return execute()\r\n}\r\n\r\n/**\r\n * A no-operation function that returns `undefined`.\r\n */\r\nexport function noop(): void {\r\n return undefined\r\n}\r\n\r\n/**\r\n * Returns the given value unchanged.\r\n *\r\n * @param value - The value to return.\r\n * @returns The same value.\r\n */\r\nexport function identity<T>(value: T): T {\r\n return value\r\n}\r\n\r\n/**\r\n * Creates a function that invokes `fn` only once. Subsequent calls return\r\n * the result of the first invocation.\r\n *\r\n * @param fn - The function to wrap.\r\n * @returns A function that runs only once.\r\n */\r\nexport function once<T extends (...args: unknown[]) => unknown>(\r\n fn: T\r\n): (...args: Parameters<T>) => ReturnType<T> {\r\n let called = false\r\n let result: ReturnType<T>\r\n\r\n return function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\r\n if (!called) {\r\n called = true\r\n result = fn.apply(this, args) as ReturnType<T>\r\n }\r\n return result\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export interface DebounceOptions {\r\n leading?: boolean\r\n trailing?: boolean\r\n maxWait?: number\r\n}\r\n\r\nexport interface DebouncedFunction<T extends (...args: unknown[]) => unknown> {\r\n (...args: Parameters<T>): void\r\n cancel(): void\r\n flush(): void\r\n}\r\n\r\nexport interface MemoizedFunction<T extends (...args: unknown[]) => unknown> {\r\n (...args: Parameters<T>): ReturnType<T>\r\n cache: Map<string, ReturnType<T>>\r\n}\r\n\r\nexport interface RetryOptions {\r\n attempts?: number\r\n baseDelay?: number\r\n maxDelay?: number\r\n shouldRetry?: (error: unknown) => boolean\r\n}\r\n\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\r\n if (value === null || typeof value !== 'object') return false\r\n const proto = Object.getPrototypeOf(value)\r\n return proto === Object.prototype || proto === null\r\n}\r\n\r\nfunction getType(value: unknown): string {\r\n return Object.prototype.toString.call(value)\r\n}\r\n\r\nfunction clone<T>(value: T, seen: WeakMap<object, unknown>): T {\r\n if (value === null || typeof value !== 'object') return value\r\n\r\n if (seen.has(value as object)) return seen.get(value as object) as T\r\n\r\n const tag = getType(value)\r\n\r\n if (tag === '[object Date]') {\r\n const cloned = new Date((value as unknown as Date).getTime())\r\n seen.set(value as object, cloned)\r\n return cloned as unknown as T\r\n }\r\n\r\n if (tag === '[object RegExp]') {\r\n const regExp = value as unknown as RegExp\r\n const cloned = new RegExp(regExp.source, regExp.flags)\r\n cloned.lastIndex = regExp.lastIndex\r\n seen.set(value as object, cloned)\r\n return cloned as unknown as T\r\n }\r\n\r\n if (tag === '[object Map]') {\r\n const cloned = new Map<unknown, unknown>()\r\n seen.set(value as object, cloned)\r\n ;(value as unknown as Map<unknown, unknown>).forEach((v, k) => {\r\n cloned.set(clone(k, seen), clone(v, seen))\r\n })\r\n return cloned as unknown as T\r\n }\r\n\r\n if (tag === '[object Set]') {\r\n const cloned = new Set<unknown>()\r\n seen.set(value as object, cloned)\r\n ;(value as unknown as Set<unknown>).forEach(v => {\r\n cloned.add(clone(v, seen))\r\n })\r\n return cloned as unknown as T\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n const cloned: unknown[] = []\r\n seen.set(value as object, cloned)\r\n for (let i = 0; i < value.length; i++) {\r\n cloned[i] = clone(value[i], seen)\r\n }\r\n return cloned as unknown as T\r\n }\r\n\r\n if (tag === '[object Object]') {\r\n const cloned: Record<string, unknown> = {}\r\n seen.set(value as object, cloned)\r\n const keys = Object.keys(value as Record<string, unknown>)\r\n for (let i = 0; i < keys.length; i++) {\r\n const key = keys[i]!\r\n cloned[key] = clone((value as Record<string, unknown>)[key], seen)\r\n }\r\n return cloned as unknown as T\r\n }\r\n\r\n return value\r\n}\r\n\r\n/**\r\n * Deep clone a value, supporting objects, arrays, Date, RegExp, Map, Set,\r\n * and cyclic references.\r\n *\r\n * @param value - The value to clone.\r\n * @returns A deep copy of the input value.\r\n */\r\nexport function deepClone<T>(value: T): T {\r\n const seen = new WeakMap<object, unknown>()\r\n return clone(value, seen)\r\n}\r\n\r\n/**\r\n * Deep merge multiple objects. Arrays are overwritten, not concatenated.\r\n * `null` and `undefined` source objects are skipped.\r\n *\r\n * @param objects - The objects to merge.\r\n * @returns A new object with merged properties.\r\n */\r\nexport function deepMerge<T extends Record<string, unknown>>(...objects: Partial<T>[]): T {\r\n const result = {} as T\r\n\r\n for (let i = 0; i < objects.length; i++) {\r\n const obj = objects[i]\r\n if (obj === null || obj === undefined) continue\r\n\r\n const keys = Object.keys(obj) as (keyof T)[]\r\n for (let j = 0; j < keys.length; j++) {\r\n const key = keys[j]!\r\n const val = obj[key]\r\n const existing = result[key]\r\n\r\n if (val !== undefined && isPlainObject(val) && isPlainObject(existing)) {\r\n result[key] = deepMerge(\r\n existing as Record<string, unknown>,\r\n val as Record<string, unknown>\r\n ) as T[keyof T]\r\n } else if (val !== undefined) {\r\n result[key] = val as T[keyof T]\r\n }\r\n }\r\n }\r\n\r\n return result\r\n}\r\n\r\n/**\r\n * Creates a debounced function that delays invoking `fn` until after `wait`\r\n * milliseconds have elapsed since the last invocation. Supports leading,\r\n * trailing, and maxWait options. The returned function also has `.cancel()`\r\n * and `.flush()` methods.\r\n *\r\n * @param fn - The function to debounce.\r\n * @param wait - The number of milliseconds to delay.\r\n * @param options - Optional configuration.\r\n * @returns A debounced function with `.cancel()` and `.flush()`.\r\n */\r\nexport function debounce<T extends (...args: unknown[]) => unknown>(\r\n fn: T,\r\n wait: number,\r\n options?: DebounceOptions\r\n): DebouncedFunction<T> {\r\n const { leading = false, trailing = true, maxWait } = options ?? {}\r\n\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n let maxTimer: ReturnType<typeof setTimeout> | null = null\r\n let lastArgs: Parameters<T> | null = null\r\n let lastCallTime: number | null = null\r\n let lastInvokeTime = 0\r\n\r\n function invoke(time: number): void {\r\n lastInvokeTime = time\r\n if (lastArgs) {\r\n fn(...lastArgs)\r\n lastArgs = null\r\n }\r\n }\r\n\r\n function startTimer(waitTime: number): void {\r\n if (timer) clearTimeout(timer)\r\n timer = setTimeout(() => {\r\n const now = Date.now()\r\n if (lastArgs && trailing) {\r\n invoke(now)\r\n }\r\n timer = null\r\n lastCallTime = null\r\n }, waitTime)\r\n }\r\n\r\n function startMaxTimer(): void {\r\n if (maxWait === undefined || maxTimer) return\r\n maxTimer = setTimeout(() => {\r\n if (lastArgs) {\r\n invoke(Date.now())\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n lastCallTime = null\r\n }\r\n }, maxWait)\r\n }\r\n\r\n function clearAllTimers(): void {\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n if (maxTimer) {\r\n clearTimeout(maxTimer)\r\n maxTimer = null\r\n }\r\n }\r\n\r\n function shouldInvoke(time: number): boolean {\r\n if (lastCallTime === null) return true\r\n const timeSinceLastCall = time - lastCallTime\r\n const timeSinceLastInvoke = time - lastInvokeTime\r\n return (\r\n timeSinceLastCall >= wait ||\r\n (maxWait !== undefined && timeSinceLastInvoke >= maxWait)\r\n )\r\n }\r\n\r\n const debounced = function (this: unknown, ...args: Parameters<T>): void {\r\n const time = Date.now()\r\n const isInvoking = shouldInvoke(time)\r\n\r\n lastArgs = args\r\n lastCallTime = time\r\n\r\n if (isInvoking && !timer && leading) {\r\n invoke(time)\r\n }\r\n\r\n if (!timer) {\r\n startTimer(wait)\r\n if (maxWait !== undefined) {\r\n startMaxTimer()\r\n }\r\n }\r\n } as DebouncedFunction<T>\r\n\r\n debounced.cancel = (): void => {\r\n clearAllTimers()\r\n lastArgs = null\r\n lastCallTime = null\r\n lastInvokeTime = 0\r\n }\r\n\r\n debounced.flush = (): void => {\r\n if (timer && lastArgs) {\r\n invoke(Date.now())\r\n clearAllTimers()\r\n lastCallTime = null\r\n }\r\n }\r\n\r\n return debounced\r\n}\r\n\r\n/**\r\n * Creates a throttled function that only invokes `fn` at most once per\r\n * `wait` milliseconds.\r\n *\r\n * @param fn - The function to throttle.\r\n * @param wait - The number of milliseconds to throttle invocations to.\r\n * @returns A throttled function.\r\n */\r\nexport function throttle<T extends (...args: unknown[]) => unknown>(\r\n fn: T,\r\n wait: number\r\n): (...args: Parameters<T>) => void {\r\n let lastTime = 0\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n let lastArgs: Parameters<T> | null = null\r\n\r\n const throttled = function (this: unknown, ...args: Parameters<T>): void {\r\n const now = Date.now()\r\n const remaining = wait - (now - lastTime)\r\n\r\n if (remaining <= 0) {\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n lastTime = now\r\n lastArgs = null\r\n fn.apply(this, args)\r\n } else {\r\n lastArgs = args\r\n if (!timer) {\r\n timer = setTimeout(() => {\r\n lastTime = Date.now()\r\n timer = null\r\n if (lastArgs) {\r\n fn.apply(this, lastArgs)\r\n lastArgs = null\r\n }\r\n }, remaining)\r\n }\r\n }\r\n }\r\n\r\n return throttled\r\n}\r\n\r\n/**\r\n * Creates a memoized version of `fn`. Uses a `Map` cache keyed by the\r\n * first argument by default, or by a custom `resolver` function.\r\n *\r\n * @param fn - The function to memoize.\r\n * @param resolver - Optional function to determine the cache key.\r\n * @returns The memoized function with a `.cache` property.\r\n */\r\nexport function memoize<T extends (...args: unknown[]) => unknown>(\r\n fn: T,\r\n resolver?: (...args: Parameters<T>) => string\r\n): MemoizedFunction<T> {\r\n const cache = new Map<string, ReturnType<T>>()\r\n\r\n const memoized = function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\r\n const key = resolver ? resolver(...args) : String(args[0])\r\n if (cache.has(key)) {\r\n return cache.get(key) as ReturnType<T>\r\n }\r\n const result = fn.apply(this, args) as ReturnType<T>\r\n cache.set(key, result)\r\n return result\r\n }\r\n\r\n memoized.cache = cache\r\n\r\n return memoized as MemoizedFunction<T>\r\n}\r\n\r\n/**\r\n * Retries an async function with exponential backoff and jitter.\r\n *\r\n * @param fn - The async function to retry.\r\n * @param options - Retry configuration.\r\n * @returns A promise that resolves with the function result.\r\n */\r\nexport function retry<T>(\r\n fn: () => Promise<T>,\r\n options?: RetryOptions\r\n): Promise<T> {\r\n const {\r\n attempts = 3,\r\n baseDelay = 1000,\r\n maxDelay = 30000,\r\n shouldRetry = () => true,\r\n } = options ?? {}\r\n\r\n let attempt = 0\r\n\r\n const execute = (): Promise<T> => {\r\n attempt++\r\n return fn().catch((error: unknown) => {\r\n if (attempt >= attempts || !shouldRetry(error)) {\r\n throw error\r\n }\r\n\r\n const delay = Math.min(\r\n baseDelay * Math.pow(2, attempt - 1) + Math.random() * baseDelay,\r\n maxDelay\r\n )\r\n\r\n return new Promise<T>(resolve => {\r\n setTimeout(() => {\r\n resolve(execute())\r\n }, delay)\r\n })\r\n })\r\n }\r\n\r\n return execute()\r\n}\r\n\r\n/**\r\n * A no-operation function that returns `undefined`.\r\n */\r\nexport function noop(): void {\r\n return undefined\r\n}\r\n\r\n/**\r\n * Returns the given value unchanged.\r\n *\r\n * @param value - The value to return.\r\n * @returns The same value.\r\n */\r\nexport function identity<T>(value: T): T {\r\n return value\r\n}\r\n\r\n/**\r\n * Creates a function that invokes `fn` only once. Subsequent calls return\r\n * the result of the first invocation.\r\n *\r\n * @param fn - The function to wrap.\r\n * @returns A function that runs only once.\r\n */\r\nexport function once<T extends (...args: unknown[]) => unknown>(\r\n fn: T\r\n): (...args: Parameters<T>) => ReturnType<T> {\r\n let called = false\r\n let result: ReturnType<T>\r\n\r\n return function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\r\n if (!called) {\r\n called = true\r\n result = fn.apply(this, args) as ReturnType<T>\r\n }\r\n return result\r\n }\r\n}\r\n\r\n/**\r\n * Deep equality check between two values. Supports primitives, objects,\r\n * arrays, Date, RegExp, Map, Set, and nested structures. Circular\r\n * references are handled.\r\n *\r\n * @example deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } }) // true\r\n * @example deepEqual({ a: 1 }, { a: 2 }) // false\r\n */\r\nexport function deepEqual(a: unknown, b: unknown): boolean {\r\n if (Object.is(a, b)) return true\r\n if (a === null || b === null || typeof a !== typeof b) return false\r\n if (typeof a !== 'object') return false\r\n\r\n const aObj = a as Record<string, unknown>\r\n const bObj = b as Record<string, unknown>\r\n\r\n if (Array.isArray(a) && Array.isArray(b)) {\r\n if (a.length !== b.length) return false\r\n for (let i = 0; i < a.length; i++) {\r\n if (!deepEqual(a[i], b[i])) return false\r\n }\r\n return true\r\n }\r\n\r\n if (a instanceof Date && b instanceof Date) {\r\n return a.getTime() === b.getTime()\r\n }\r\n\r\n if (a instanceof RegExp && b instanceof RegExp) {\r\n return a.source === b.source && a.flags === b.flags\r\n }\r\n\r\n if (a instanceof Map && b instanceof Map) {\r\n if (a.size !== b.size) return false\r\n for (const [k, v] of a) {\r\n if (!b.has(k) || !deepEqual(v, b.get(k))) return false\r\n }\r\n return true\r\n }\r\n\r\n if (a instanceof Set && b instanceof Set) {\r\n if (a.size !== b.size) return false\r\n for (const v of a) {\r\n if (!b.has(v)) return false\r\n }\r\n return true\r\n }\r\n\r\n const keysA = Object.keys(aObj)\r\n const keysB = Object.keys(bObj)\r\n if (keysA.length !== keysB.length) return false\r\n\r\n for (const key of keysA) {\r\n if (!Object.prototype.hasOwnProperty.call(bObj, key)) return false\r\n if (!deepEqual(aObj[key], bObj[key])) return false\r\n }\r\n return true\r\n}\r\n\r\n/**\r\n * Performs left-to-right function composition.\r\n *\r\n * @example const fn = pipe((x: number) => x + 1, (x: number) => x * 2)\r\n * fn(3) // 8\r\n */\r\nexport function pipe<T>(initial: T, ...fns: Array<(arg: T) => T>): T\r\nexport function pipe<T, R>(initial: T, ...fns: Array<(arg: unknown) => unknown>): R\r\nexport function pipe(initial: unknown, ...fns: Array<(arg: unknown) => unknown>): unknown {\r\n return fns.reduce((acc, fn) => fn(acc), initial)\r\n}\r\n\r\n/**\r\n * Performs right-to-left function composition.\r\n *\r\n * @example const fn = compose((x: number) => x * 2, (x: number) => x + 1)\r\n * fn(3) // 8 — same as (3+1)*2\r\n */\r\nexport function compose<T>(...fns: Array<(arg: T) => T>): (initial: T) => T\r\nexport function compose(...fns: Array<(arg: unknown) => unknown>): (initial: unknown) => unknown {\r\n return (initial: unknown) => fns.reduceRight((acc, fn) => fn(acc), initial)\r\n}\r\n"],"mappings":"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","names":[]}
|