@zuwy/frontend-engineering-system-utils 0.1.0 → 0.2.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 +17 -17
- package/dist/array.d.ts +60 -0
- package/dist/array.js +95 -0
- package/dist/async.d.ts +40 -0
- package/dist/async.js +50 -0
- package/dist/function.d.ts +76 -0
- package/dist/function.js +122 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/number.d.ts +29 -0
- package/dist/number.js +35 -0
- package/dist/object.d.ts +44 -0
- package/dist/object.js +77 -0
- package/dist/string.d.ts +54 -0
- package/dist/string.js +77 -0
- package/dist/type.d.ts +64 -0
- package/dist/type.js +88 -0
- package/package.json +11 -12
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# @zuwy/frontend-engineering-system-utils
|
|
2
|
-
|
|
3
|
-
Shared utility functions for frontend-engineering-system.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
pnpm add @zuwy/frontend-engineering-system-utils
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Usage
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { readBoolean } from "@zuwy/frontend-engineering-system-utils"
|
|
15
|
-
|
|
16
|
-
readBoolean("true")
|
|
17
|
-
```
|
|
1
|
+
# @zuwy/frontend-engineering-system-utils
|
|
2
|
+
|
|
3
|
+
Shared utility functions for frontend-engineering-system.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @zuwy/frontend-engineering-system-utils
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { readBoolean } from "@zuwy/frontend-engineering-system-utils"
|
|
15
|
+
|
|
16
|
+
readBoolean("true")
|
|
17
|
+
```
|
package/dist/array.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes duplicate values, keeping the first occurrence.
|
|
3
|
+
*
|
|
4
|
+
* @param array - The source array.
|
|
5
|
+
* @returns A new array without duplicates.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* unique([1, 2, 2, 3, 3, 3]) // [1, 2, 3]
|
|
10
|
+
* unique(["a", "a", "b"]) // ["a", "b"]
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function unique<T>(array: readonly T[]): T[];
|
|
14
|
+
/**
|
|
15
|
+
* Removes duplicates based on a derived key, keeping the first occurrence.
|
|
16
|
+
*
|
|
17
|
+
* @param array - The source array.
|
|
18
|
+
* @param keySelector - Returns the key used to detect duplicates.
|
|
19
|
+
* @returns A new array without duplicates.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const users = [
|
|
24
|
+
* { id: 1, name: "Alice" },
|
|
25
|
+
* { id: 1, name: "Alice (dup)" },
|
|
26
|
+
* { id: 2, name: "Bob" },
|
|
27
|
+
* ]
|
|
28
|
+
* uniqueBy(users, (user) => user.id)
|
|
29
|
+
* // [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function uniqueBy<T, K>(array: readonly T[], keySelector: (item: T) => K): T[];
|
|
33
|
+
/**
|
|
34
|
+
* Splits an array into groups of the given size. The last group may be shorter.
|
|
35
|
+
*
|
|
36
|
+
* @param array - The source array.
|
|
37
|
+
* @param size - The length of each group. Must be a positive integer.
|
|
38
|
+
* @returns A new array of chunked arrays.
|
|
39
|
+
* @throws {RangeError} When `size` is not a positive integer.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function chunk<T>(array: readonly T[], size: number): T[][];
|
|
47
|
+
/**
|
|
48
|
+
* Groups the items of an array by a derived key.
|
|
49
|
+
*
|
|
50
|
+
* @param array - The source array.
|
|
51
|
+
* @param keySelector - Returns the group key for each item.
|
|
52
|
+
* @returns An object mapping each key to the list of matching items.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* groupBy([1, 2, 3, 4], (n) => (n % 2 === 0 ? "even" : "odd"))
|
|
57
|
+
* // { odd: [1, 3], even: [2, 4] }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function groupBy<T, K extends PropertyKey>(array: readonly T[], keySelector: (item: T) => K): Record<K, T[]>;
|
package/dist/array.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes duplicate values, keeping the first occurrence.
|
|
3
|
+
*
|
|
4
|
+
* @param array - The source array.
|
|
5
|
+
* @returns A new array without duplicates.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* unique([1, 2, 2, 3, 3, 3]) // [1, 2, 3]
|
|
10
|
+
* unique(["a", "a", "b"]) // ["a", "b"]
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export function unique(array) {
|
|
14
|
+
return Array.from(new Set(array));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Removes duplicates based on a derived key, keeping the first occurrence.
|
|
18
|
+
*
|
|
19
|
+
* @param array - The source array.
|
|
20
|
+
* @param keySelector - Returns the key used to detect duplicates.
|
|
21
|
+
* @returns A new array without duplicates.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const users = [
|
|
26
|
+
* { id: 1, name: "Alice" },
|
|
27
|
+
* { id: 1, name: "Alice (dup)" },
|
|
28
|
+
* { id: 2, name: "Bob" },
|
|
29
|
+
* ]
|
|
30
|
+
* uniqueBy(users, (user) => user.id)
|
|
31
|
+
* // [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function uniqueBy(array, keySelector) {
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
const result = [];
|
|
37
|
+
for (const item of array) {
|
|
38
|
+
const key = keySelector(item);
|
|
39
|
+
if (!seen.has(key)) {
|
|
40
|
+
seen.add(key);
|
|
41
|
+
result.push(item);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Splits an array into groups of the given size. The last group may be shorter.
|
|
48
|
+
*
|
|
49
|
+
* @param array - The source array.
|
|
50
|
+
* @param size - The length of each group. Must be a positive integer.
|
|
51
|
+
* @returns A new array of chunked arrays.
|
|
52
|
+
* @throws {RangeError} When `size` is not a positive integer.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function chunk(array, size) {
|
|
60
|
+
if (!Number.isInteger(size) || size <= 0) {
|
|
61
|
+
throw new RangeError("chunk size must be a positive integer");
|
|
62
|
+
}
|
|
63
|
+
const result = [];
|
|
64
|
+
for (let index = 0; index < array.length; index += size) {
|
|
65
|
+
result.push(array.slice(index, index + size));
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Groups the items of an array by a derived key.
|
|
71
|
+
*
|
|
72
|
+
* @param array - The source array.
|
|
73
|
+
* @param keySelector - Returns the group key for each item.
|
|
74
|
+
* @returns An object mapping each key to the list of matching items.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* groupBy([1, 2, 3, 4], (n) => (n % 2 === 0 ? "even" : "odd"))
|
|
79
|
+
* // { odd: [1, 3], even: [2, 4] }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function groupBy(array, keySelector) {
|
|
83
|
+
const result = {};
|
|
84
|
+
for (const item of array) {
|
|
85
|
+
const key = keySelector(item);
|
|
86
|
+
const group = result[key];
|
|
87
|
+
if (group) {
|
|
88
|
+
group.push(item);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
result[key] = [item];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
package/dist/async.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pauses execution for the given duration.
|
|
3
|
+
*
|
|
4
|
+
* @param duration - Milliseconds to wait.
|
|
5
|
+
* @returns A promise that resolves after the duration.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* console.log("start")
|
|
10
|
+
* await sleep(1000)
|
|
11
|
+
* console.log("one second later")
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function sleep(duration: number): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Options for {@link retry}.
|
|
17
|
+
*/
|
|
18
|
+
export interface RetryOptions {
|
|
19
|
+
/** Maximum number of retries, excluding the first attempt. Defaults to 3. */
|
|
20
|
+
retries?: number;
|
|
21
|
+
/** Milliseconds to wait before each retry. Defaults to 0. */
|
|
22
|
+
delay?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Runs a function and retries it until it succeeds or the retry limit is reached.
|
|
26
|
+
*
|
|
27
|
+
* @param fn - The function to execute. It may return a value or a promise.
|
|
28
|
+
* @param options - Retry options.
|
|
29
|
+
* @returns The resolved value of `fn`.
|
|
30
|
+
* @throws The last error thrown by `fn` when all attempts fail.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const data = await retry(() => fetch("/api/data").then((res) => res.json()), {
|
|
35
|
+
* retries: 3,
|
|
36
|
+
* delay: 500,
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function retry<T>(fn: () => Promise<T> | T, options?: RetryOptions): Promise<T>;
|
package/dist/async.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pauses execution for the given duration.
|
|
3
|
+
*
|
|
4
|
+
* @param duration - Milliseconds to wait.
|
|
5
|
+
* @returns A promise that resolves after the duration.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* console.log("start")
|
|
10
|
+
* await sleep(1000)
|
|
11
|
+
* console.log("one second later")
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export function sleep(duration) {
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
setTimeout(resolve, duration);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Runs a function and retries it until it succeeds or the retry limit is reached.
|
|
21
|
+
*
|
|
22
|
+
* @param fn - The function to execute. It may return a value or a promise.
|
|
23
|
+
* @param options - Retry options.
|
|
24
|
+
* @returns The resolved value of `fn`.
|
|
25
|
+
* @throws The last error thrown by `fn` when all attempts fail.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const data = await retry(() => fetch("/api/data").then((res) => res.json()), {
|
|
30
|
+
* retries: 3,
|
|
31
|
+
* delay: 500,
|
|
32
|
+
* })
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export async function retry(fn, options = {}) {
|
|
36
|
+
const { retries = 3, delay = 0 } = options;
|
|
37
|
+
let lastError;
|
|
38
|
+
for (let attempt = 0; attempt <= retries; attempt += 1) {
|
|
39
|
+
try {
|
|
40
|
+
return await fn();
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
lastError = error;
|
|
44
|
+
if (attempt < retries && delay > 0) {
|
|
45
|
+
await sleep(delay);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
throw lastError;
|
|
50
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A debounced function returned by {@link debounce}.
|
|
3
|
+
*/
|
|
4
|
+
export interface DebouncedFunction<Args extends unknown[]> {
|
|
5
|
+
(...args: Args): void;
|
|
6
|
+
/** Cancels the pending invocation, if any. */
|
|
7
|
+
cancel: () => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Creates a debounced function that delays invoking `fn` until `wait`
|
|
11
|
+
* milliseconds have elapsed since the last call.
|
|
12
|
+
*
|
|
13
|
+
* @param fn - The function to debounce.
|
|
14
|
+
* @param wait - Delay in milliseconds. Defaults to 300.
|
|
15
|
+
* @returns A debounced function with a `cancel` method.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const search = debounce((keyword: string) => {
|
|
20
|
+
* console.log("searching:", keyword)
|
|
21
|
+
* }, 300)
|
|
22
|
+
*
|
|
23
|
+
* search("a")
|
|
24
|
+
* search("ab") // only "ab" is logged, 300ms after the last call
|
|
25
|
+
* search.cancel() // cancels the pending invocation
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function debounce<Args extends unknown[]>(fn: (...args: Args) => void, wait?: number): DebouncedFunction<Args>;
|
|
29
|
+
/**
|
|
30
|
+
* A throttled function returned by {@link throttle}.
|
|
31
|
+
*/
|
|
32
|
+
export interface ThrottledFunction<Args extends unknown[]> {
|
|
33
|
+
(...args: Args): void;
|
|
34
|
+
/** Cancels the trailing invocation, if any. */
|
|
35
|
+
cancel: () => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Creates a throttled function that invokes `fn` at most once per `wait`
|
|
39
|
+
* milliseconds. Calls made during the window are invoked at the end of it.
|
|
40
|
+
*
|
|
41
|
+
* @param fn - The function to throttle.
|
|
42
|
+
* @param wait - Minimum interval between invocations in milliseconds. Defaults to 300.
|
|
43
|
+
* @returns A throttled function with a `cancel` method.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const onScroll = throttle(() => {
|
|
48
|
+
* console.log(window.scrollY)
|
|
49
|
+
* }, 200)
|
|
50
|
+
*
|
|
51
|
+
* window.addEventListener("scroll", onScroll)
|
|
52
|
+
* // ...later
|
|
53
|
+
* window.removeEventListener("scroll", onScroll)
|
|
54
|
+
* onScroll.cancel()
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function throttle<Args extends unknown[]>(fn: (...args: Args) => void, wait?: number): ThrottledFunction<Args>;
|
|
58
|
+
/**
|
|
59
|
+
* Wraps a function so it is executed only once. Subsequent calls return the
|
|
60
|
+
* result of the first invocation.
|
|
61
|
+
*
|
|
62
|
+
* @param fn - The function to wrap.
|
|
63
|
+
* @returns A function that runs `fn` at most once.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const init = once(() => {
|
|
68
|
+
* console.log("initialized")
|
|
69
|
+
* return 42
|
|
70
|
+
* })
|
|
71
|
+
*
|
|
72
|
+
* init() // logs "initialized", returns 42
|
|
73
|
+
* init() // returns 42 without logging again
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function once<Args extends unknown[], R>(fn: (...args: Args) => R): (...args: Args) => R;
|
package/dist/function.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a debounced function that delays invoking `fn` until `wait`
|
|
3
|
+
* milliseconds have elapsed since the last call.
|
|
4
|
+
*
|
|
5
|
+
* @param fn - The function to debounce.
|
|
6
|
+
* @param wait - Delay in milliseconds. Defaults to 300.
|
|
7
|
+
* @returns A debounced function with a `cancel` method.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const search = debounce((keyword: string) => {
|
|
12
|
+
* console.log("searching:", keyword)
|
|
13
|
+
* }, 300)
|
|
14
|
+
*
|
|
15
|
+
* search("a")
|
|
16
|
+
* search("ab") // only "ab" is logged, 300ms after the last call
|
|
17
|
+
* search.cancel() // cancels the pending invocation
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function debounce(fn, wait = 300) {
|
|
21
|
+
let timer;
|
|
22
|
+
const cancel = () => {
|
|
23
|
+
if (timer !== undefined) {
|
|
24
|
+
clearTimeout(timer);
|
|
25
|
+
timer = undefined;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const debounced = (...args) => {
|
|
29
|
+
cancel();
|
|
30
|
+
timer = setTimeout(() => {
|
|
31
|
+
timer = undefined;
|
|
32
|
+
fn(...args);
|
|
33
|
+
}, wait);
|
|
34
|
+
};
|
|
35
|
+
return Object.assign(debounced, { cancel });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Creates a throttled function that invokes `fn` at most once per `wait`
|
|
39
|
+
* milliseconds. Calls made during the window are invoked at the end of it.
|
|
40
|
+
*
|
|
41
|
+
* @param fn - The function to throttle.
|
|
42
|
+
* @param wait - Minimum interval between invocations in milliseconds. Defaults to 300.
|
|
43
|
+
* @returns A throttled function with a `cancel` method.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const onScroll = throttle(() => {
|
|
48
|
+
* console.log(window.scrollY)
|
|
49
|
+
* }, 200)
|
|
50
|
+
*
|
|
51
|
+
* window.addEventListener("scroll", onScroll)
|
|
52
|
+
* // ...later
|
|
53
|
+
* window.removeEventListener("scroll", onScroll)
|
|
54
|
+
* onScroll.cancel()
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function throttle(fn, wait = 300) {
|
|
58
|
+
let lastCall = 0;
|
|
59
|
+
let timer;
|
|
60
|
+
let lastArgs;
|
|
61
|
+
const invoke = () => {
|
|
62
|
+
lastCall = Date.now();
|
|
63
|
+
timer = undefined;
|
|
64
|
+
if (lastArgs !== undefined) {
|
|
65
|
+
fn(...lastArgs);
|
|
66
|
+
lastArgs = undefined;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const cancel = () => {
|
|
70
|
+
if (timer !== undefined) {
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
timer = undefined;
|
|
73
|
+
}
|
|
74
|
+
lastArgs = undefined;
|
|
75
|
+
lastCall = 0;
|
|
76
|
+
};
|
|
77
|
+
const throttled = (...args) => {
|
|
78
|
+
lastArgs = args;
|
|
79
|
+
const remaining = wait - (Date.now() - lastCall);
|
|
80
|
+
if (remaining <= 0) {
|
|
81
|
+
if (timer !== undefined) {
|
|
82
|
+
clearTimeout(timer);
|
|
83
|
+
timer = undefined;
|
|
84
|
+
}
|
|
85
|
+
invoke();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (timer === undefined) {
|
|
89
|
+
timer = setTimeout(invoke, remaining);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
return Object.assign(throttled, { cancel });
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Wraps a function so it is executed only once. Subsequent calls return the
|
|
96
|
+
* result of the first invocation.
|
|
97
|
+
*
|
|
98
|
+
* @param fn - The function to wrap.
|
|
99
|
+
* @returns A function that runs `fn` at most once.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* const init = once(() => {
|
|
104
|
+
* console.log("initialized")
|
|
105
|
+
* return 42
|
|
106
|
+
* })
|
|
107
|
+
*
|
|
108
|
+
* init() // logs "initialized", returns 42
|
|
109
|
+
* init() // returns 42 without logging again
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export function once(fn) {
|
|
113
|
+
let called = false;
|
|
114
|
+
let result;
|
|
115
|
+
return (...args) => {
|
|
116
|
+
if (!called) {
|
|
117
|
+
called = true;
|
|
118
|
+
result = fn(...args);
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
};
|
|
122
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
1
|
export { readBoolean } from "./boolean.js";
|
|
2
|
+
export { isNil, isDefined, isPlainObject, isEmpty } from "./type.js";
|
|
3
|
+
export { unique, uniqueBy, chunk, groupBy } from "./array.js";
|
|
4
|
+
export { pick, omit, deepClone } from "./object.js";
|
|
5
|
+
export { capitalize, truncate, camelCase, kebabCase } from "./string.js";
|
|
6
|
+
export { clamp, randomInt } from "./number.js";
|
|
7
|
+
export { debounce, throttle, once } from "./function.js";
|
|
8
|
+
export type { DebouncedFunction, ThrottledFunction } from "./function.js";
|
|
9
|
+
export { sleep, retry } from "./async.js";
|
|
10
|
+
export type { RetryOptions } from "./async.js";
|
package/dist/index.js
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
1
|
export { readBoolean } from "./boolean.js";
|
|
2
|
+
export { isNil, isDefined, isPlainObject, isEmpty } from "./type.js";
|
|
3
|
+
export { unique, uniqueBy, chunk, groupBy } from "./array.js";
|
|
4
|
+
export { pick, omit, deepClone } from "./object.js";
|
|
5
|
+
export { capitalize, truncate, camelCase, kebabCase } from "./string.js";
|
|
6
|
+
export { clamp, randomInt } from "./number.js";
|
|
7
|
+
export { debounce, throttle, once } from "./function.js";
|
|
8
|
+
export { sleep, retry } from "./async.js";
|
package/dist/number.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clamps a number within the inclusive `min` and `max` bounds.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The number to clamp.
|
|
5
|
+
* @param min - The lower bound.
|
|
6
|
+
* @param max - The upper bound.
|
|
7
|
+
* @returns The clamped number.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* clamp(5, 0, 10) // 5
|
|
12
|
+
* clamp(-1, 0, 10) // 0
|
|
13
|
+
* clamp(99, 0, 10) // 10
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function clamp(value: number, min: number, max: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Returns a random integer between `min` and `max`, both inclusive.
|
|
19
|
+
*
|
|
20
|
+
* @param min - The lower bound.
|
|
21
|
+
* @param max - The upper bound.
|
|
22
|
+
* @returns A random integer within `[min, max]`.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* randomInt(1, 6) // e.g. 4
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function randomInt(min: number, max: number): number;
|
package/dist/number.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clamps a number within the inclusive `min` and `max` bounds.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The number to clamp.
|
|
5
|
+
* @param min - The lower bound.
|
|
6
|
+
* @param max - The upper bound.
|
|
7
|
+
* @returns The clamped number.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* clamp(5, 0, 10) // 5
|
|
12
|
+
* clamp(-1, 0, 10) // 0
|
|
13
|
+
* clamp(99, 0, 10) // 10
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function clamp(value, min, max) {
|
|
17
|
+
return Math.min(Math.max(value, min), max);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Returns a random integer between `min` and `max`, both inclusive.
|
|
21
|
+
*
|
|
22
|
+
* @param min - The lower bound.
|
|
23
|
+
* @param max - The upper bound.
|
|
24
|
+
* @returns A random integer within `[min, max]`.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* randomInt(1, 6) // e.g. 4
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function randomInt(min, max) {
|
|
32
|
+
const lower = Math.ceil(min);
|
|
33
|
+
const upper = Math.floor(max);
|
|
34
|
+
return Math.floor(Math.random() * (upper - lower + 1)) + lower;
|
|
35
|
+
}
|
package/dist/object.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a new object containing only the picked properties.
|
|
3
|
+
*
|
|
4
|
+
* @param object - The source object.
|
|
5
|
+
* @param keys - The property keys to pick.
|
|
6
|
+
* @returns A new object with only the picked properties.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* pick({ id: 1, name: "Alice", age: 30 }, ["id", "name"])
|
|
11
|
+
* // { id: 1, name: "Alice" }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function pick<T extends object, K extends keyof T>(object: T, keys: readonly K[]): Pick<T, K>;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a shallow copy of an object without the omitted properties.
|
|
17
|
+
*
|
|
18
|
+
* @param object - The source object.
|
|
19
|
+
* @param keys - The property keys to omit.
|
|
20
|
+
* @returns A shallow copy without the omitted properties.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* omit({ id: 1, name: "Alice", age: 30 }, ["age"])
|
|
25
|
+
* // { id: 1, name: "Alice" }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function omit<T extends object, K extends keyof T>(object: T, keys: readonly K[]): Omit<T, K>;
|
|
29
|
+
/**
|
|
30
|
+
* Creates a deep clone of the given value. Plain objects, arrays and `Date`
|
|
31
|
+
* instances are cloned recursively, while other values are returned as-is.
|
|
32
|
+
*
|
|
33
|
+
* @param value - The value to clone.
|
|
34
|
+
* @returns A deep clone of the value.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const source = { user: { name: "Alice" }, tags: ["a"] }
|
|
39
|
+
* const copy = deepClone(source)
|
|
40
|
+
* copy.user.name = "Bob"
|
|
41
|
+
* source.user.name // "Alice" (the original is untouched)
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function deepClone<T>(value: T): T;
|
package/dist/object.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { isPlainObject } from "./type.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a new object containing only the picked properties.
|
|
4
|
+
*
|
|
5
|
+
* @param object - The source object.
|
|
6
|
+
* @param keys - The property keys to pick.
|
|
7
|
+
* @returns A new object with only the picked properties.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* pick({ id: 1, name: "Alice", age: 30 }, ["id", "name"])
|
|
12
|
+
* // { id: 1, name: "Alice" }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function pick(object, keys) {
|
|
16
|
+
const result = {};
|
|
17
|
+
for (const key of keys) {
|
|
18
|
+
if (key in object) {
|
|
19
|
+
result[key] = object[key];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates a shallow copy of an object without the omitted properties.
|
|
26
|
+
*
|
|
27
|
+
* @param object - The source object.
|
|
28
|
+
* @param keys - The property keys to omit.
|
|
29
|
+
* @returns A shallow copy without the omitted properties.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* omit({ id: 1, name: "Alice", age: 30 }, ["age"])
|
|
34
|
+
* // { id: 1, name: "Alice" }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function omit(object, keys) {
|
|
38
|
+
const result = { ...object };
|
|
39
|
+
for (const key of keys) {
|
|
40
|
+
delete result[key];
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
function clone(value) {
|
|
45
|
+
if (Array.isArray(value)) {
|
|
46
|
+
return value.map((item) => clone(item));
|
|
47
|
+
}
|
|
48
|
+
if (value instanceof Date) {
|
|
49
|
+
return new Date(value.getTime());
|
|
50
|
+
}
|
|
51
|
+
if (isPlainObject(value)) {
|
|
52
|
+
const result = {};
|
|
53
|
+
for (const [key, item] of Object.entries(value)) {
|
|
54
|
+
result[key] = clone(item);
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Creates a deep clone of the given value. Plain objects, arrays and `Date`
|
|
62
|
+
* instances are cloned recursively, while other values are returned as-is.
|
|
63
|
+
*
|
|
64
|
+
* @param value - The value to clone.
|
|
65
|
+
* @returns A deep clone of the value.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const source = { user: { name: "Alice" }, tags: ["a"] }
|
|
70
|
+
* const copy = deepClone(source)
|
|
71
|
+
* copy.user.name = "Bob"
|
|
72
|
+
* source.user.name // "Alice" (the original is untouched)
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function deepClone(value) {
|
|
76
|
+
return clone(value);
|
|
77
|
+
}
|
package/dist/string.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts the first character of a string to upper case.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The source string.
|
|
5
|
+
* @returns A new string with the first character upper-cased.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* capitalize("hello") // "Hello"
|
|
10
|
+
* capitalize("") // ""
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function capitalize(value: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Truncates a string to the given length, appending a suffix when it is cut.
|
|
16
|
+
*
|
|
17
|
+
* @param value - The source string.
|
|
18
|
+
* @param maxLength - Maximum length of the result, including the suffix.
|
|
19
|
+
* @param suffix - Appended when the string is truncated. Defaults to `"..."`.
|
|
20
|
+
* @returns The truncated string.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* truncate("Hello, world!", 8) // "Hello..."
|
|
25
|
+
* truncate("Hi", 8) // "Hi"
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function truncate(value: string, maxLength: number, suffix?: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Converts a string to camelCase.
|
|
31
|
+
*
|
|
32
|
+
* @param value - The source string. Segments may be separated by `-`, `_` or whitespace.
|
|
33
|
+
* @returns The camelCased string.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* camelCase("foo-bar baz") // "fooBarBaz"
|
|
38
|
+
* camelCase("FOO_BAR") // "fooBar"
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function camelCase(value: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Converts a string to kebab-case.
|
|
44
|
+
*
|
|
45
|
+
* @param value - The source string. camelCase boundaries, whitespace and `_` become `-`.
|
|
46
|
+
* @returns The kebab-cased string.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* kebabCase("fooBar") // "foo-bar"
|
|
51
|
+
* kebabCase("Foo_Bar baz") // "foo-bar-baz"
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare function kebabCase(value: string): string;
|
package/dist/string.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts the first character of a string to upper case.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The source string.
|
|
5
|
+
* @returns A new string with the first character upper-cased.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* capitalize("hello") // "Hello"
|
|
10
|
+
* capitalize("") // ""
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export function capitalize(value) {
|
|
14
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Truncates a string to the given length, appending a suffix when it is cut.
|
|
18
|
+
*
|
|
19
|
+
* @param value - The source string.
|
|
20
|
+
* @param maxLength - Maximum length of the result, including the suffix.
|
|
21
|
+
* @param suffix - Appended when the string is truncated. Defaults to `"..."`.
|
|
22
|
+
* @returns The truncated string.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* truncate("Hello, world!", 8) // "Hello..."
|
|
27
|
+
* truncate("Hi", 8) // "Hi"
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function truncate(value, maxLength, suffix = "...") {
|
|
31
|
+
if (value.length <= maxLength) {
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
return value.slice(0, Math.max(0, maxLength - suffix.length)) + suffix;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Converts a string to camelCase.
|
|
38
|
+
*
|
|
39
|
+
* @param value - The source string. Segments may be separated by `-`, `_` or whitespace.
|
|
40
|
+
* @returns The camelCased string.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* camelCase("foo-bar baz") // "fooBarBaz"
|
|
45
|
+
* camelCase("FOO_BAR") // "fooBar"
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function camelCase(value) {
|
|
49
|
+
return value
|
|
50
|
+
.split(/[-_\s]+/)
|
|
51
|
+
.filter((word) => word.length > 0)
|
|
52
|
+
.map((word, index) => {
|
|
53
|
+
const lower = word.toLowerCase();
|
|
54
|
+
return index === 0 ? lower : capitalize(lower);
|
|
55
|
+
})
|
|
56
|
+
.join("");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Converts a string to kebab-case.
|
|
60
|
+
*
|
|
61
|
+
* @param value - The source string. camelCase boundaries, whitespace and `_` become `-`.
|
|
62
|
+
* @returns The kebab-cased string.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* kebabCase("fooBar") // "foo-bar"
|
|
67
|
+
* kebabCase("Foo_Bar baz") // "foo-bar-baz"
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function kebabCase(value) {
|
|
71
|
+
return value
|
|
72
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
73
|
+
.replace(/[\s_]+/g, "-")
|
|
74
|
+
.replace(/-+/g, "-")
|
|
75
|
+
.replace(/^-|-$/g, "")
|
|
76
|
+
.toLowerCase();
|
|
77
|
+
}
|
package/dist/type.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether a value is `null` or `undefined`.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The value to check.
|
|
5
|
+
* @returns `true` when the value is `null` or `undefined`.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* isNil(null) // true
|
|
10
|
+
* isNil(undefined) // true
|
|
11
|
+
* isNil(0) // false
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function isNil(value: unknown): value is null | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Checks whether a value is neither `null` nor `undefined`, narrowing the type.
|
|
17
|
+
*
|
|
18
|
+
* @param value - The value to check.
|
|
19
|
+
* @returns `true` when the value is defined.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* isDefined(0) // true
|
|
24
|
+
* isDefined("") // true
|
|
25
|
+
* isDefined(null) // false
|
|
26
|
+
*
|
|
27
|
+
* const list = [1, null, 2].filter(isDefined) // number[]
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function isDefined<T>(value: T | null | undefined): value is T;
|
|
31
|
+
/**
|
|
32
|
+
* Checks whether a value is a plain object, e.g. created via `{}` or `new Object()`.
|
|
33
|
+
* Arrays, class instances, `Date`, `Map` and `null` are not considered plain objects.
|
|
34
|
+
*
|
|
35
|
+
* @param value - The value to check.
|
|
36
|
+
* @returns `true` when the value is a plain object.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* isPlainObject({}) // true
|
|
41
|
+
* isPlainObject(Object.create(null)) // true
|
|
42
|
+
* isPlainObject([]) // false
|
|
43
|
+
* isPlainObject(new Date()) // false
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* Checks whether a value is "empty". `null`/`undefined`, empty strings and arrays,
|
|
49
|
+
* empty `Map`/`Set` and plain objects without own keys are treated as empty.
|
|
50
|
+
*
|
|
51
|
+
* @param value - The value to check.
|
|
52
|
+
* @returns `true` when the value is empty.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* isEmpty(null) // true
|
|
57
|
+
* isEmpty("") // true
|
|
58
|
+
* isEmpty([]) // true
|
|
59
|
+
* isEmpty(new Map()) // true
|
|
60
|
+
* isEmpty({}) // true
|
|
61
|
+
* isEmpty({ a: 1 }) // false
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function isEmpty(value: unknown): boolean;
|
package/dist/type.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether a value is `null` or `undefined`.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The value to check.
|
|
5
|
+
* @returns `true` when the value is `null` or `undefined`.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* isNil(null) // true
|
|
10
|
+
* isNil(undefined) // true
|
|
11
|
+
* isNil(0) // false
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export function isNil(value) {
|
|
15
|
+
return value === null || value === undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Checks whether a value is neither `null` nor `undefined`, narrowing the type.
|
|
19
|
+
*
|
|
20
|
+
* @param value - The value to check.
|
|
21
|
+
* @returns `true` when the value is defined.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* isDefined(0) // true
|
|
26
|
+
* isDefined("") // true
|
|
27
|
+
* isDefined(null) // false
|
|
28
|
+
*
|
|
29
|
+
* const list = [1, null, 2].filter(isDefined) // number[]
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function isDefined(value) {
|
|
33
|
+
return value !== null && value !== undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Checks whether a value is a plain object, e.g. created via `{}` or `new Object()`.
|
|
37
|
+
* Arrays, class instances, `Date`, `Map` and `null` are not considered plain objects.
|
|
38
|
+
*
|
|
39
|
+
* @param value - The value to check.
|
|
40
|
+
* @returns `true` when the value is a plain object.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* isPlainObject({}) // true
|
|
45
|
+
* isPlainObject(Object.create(null)) // true
|
|
46
|
+
* isPlainObject([]) // false
|
|
47
|
+
* isPlainObject(new Date()) // false
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function isPlainObject(value) {
|
|
51
|
+
if (typeof value !== "object" || value === null) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const prototype = Object.getPrototypeOf(value);
|
|
55
|
+
return prototype === Object.prototype || prototype === null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Checks whether a value is "empty". `null`/`undefined`, empty strings and arrays,
|
|
59
|
+
* empty `Map`/`Set` and plain objects without own keys are treated as empty.
|
|
60
|
+
*
|
|
61
|
+
* @param value - The value to check.
|
|
62
|
+
* @returns `true` when the value is empty.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* isEmpty(null) // true
|
|
67
|
+
* isEmpty("") // true
|
|
68
|
+
* isEmpty([]) // true
|
|
69
|
+
* isEmpty(new Map()) // true
|
|
70
|
+
* isEmpty({}) // true
|
|
71
|
+
* isEmpty({ a: 1 }) // false
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export function isEmpty(value) {
|
|
75
|
+
if (isNil(value)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
if (typeof value === "string" || Array.isArray(value)) {
|
|
79
|
+
return value.length === 0;
|
|
80
|
+
}
|
|
81
|
+
if (value instanceof Map || value instanceof Set) {
|
|
82
|
+
return value.size === 0;
|
|
83
|
+
}
|
|
84
|
+
if (isPlainObject(value)) {
|
|
85
|
+
return Object.keys(value).length === 0;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zuwy/frontend-engineering-system-utils",
|
|
3
3
|
"author": "Wenyin Zu",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"description": "Shared utility functions for @zuwy/frontend-engineering-system.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"private": false,
|
|
@@ -20,23 +20,22 @@
|
|
|
20
20
|
"README.md",
|
|
21
21
|
"LICENSE"
|
|
22
22
|
],
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "tsc -p tsconfig.build.json",
|
|
25
|
-
"lint": "eslint .",
|
|
26
|
-
"typecheck": "tsc --noEmit",
|
|
27
|
-
"pack:check": "npm pack --dry-run",
|
|
28
|
-
"prepublishOnly": "pnpm lint && pnpm typecheck && pnpm build && pnpm pack:check"
|
|
29
|
-
},
|
|
30
23
|
"publishConfig": {
|
|
31
24
|
"registry": "https://registry.npmjs.org/",
|
|
32
25
|
"access": "public"
|
|
33
26
|
},
|
|
34
27
|
"devDependencies": {
|
|
35
|
-
"@zuwy/frontend-engineering-system-eslint-config": "workspace:*",
|
|
36
|
-
"@zuwy/frontend-engineering-system-ts-config": "workspace:*",
|
|
37
28
|
"typescript": "~6.0.2",
|
|
38
29
|
"eslint": "^10.5.0",
|
|
39
30
|
"eslint-config-prettier": "^10.1.8",
|
|
40
|
-
"typescript-eslint": "^8.61.0"
|
|
31
|
+
"typescript-eslint": "^8.61.0",
|
|
32
|
+
"@zuwy/frontend-engineering-system-eslint-config": "0.0.0",
|
|
33
|
+
"@zuwy/frontend-engineering-system-ts-config": "1.0.0"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -p tsconfig.build.json",
|
|
37
|
+
"lint": "eslint .",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"pack:check": "npm pack --dry-run"
|
|
41
40
|
}
|
|
42
|
-
}
|
|
41
|
+
}
|