@cloudcome/utils-core 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/LICENSE +21 -0
- package/package.json +279 -1
- package/src/array.ts +312 -0
- package/src/async.ts +379 -0
- package/src/base64.ts +20 -0
- package/src/cache.ts +146 -0
- package/{dist/color/contrast.d.ts → src/color/contrast.ts} +12 -2
- package/src/color/distance.ts +28 -0
- package/src/color/helpers.ts +23 -0
- package/src/color/hex-hsl.ts +11 -0
- package/{dist/color/hex-hsv.d.ts → src/color/hex-hsv.ts} +11 -3
- package/{dist/color/hex-hwb.d.ts → src/color/hex-hwb.ts} +11 -3
- package/src/color/hex-rgb.ts +39 -0
- package/{dist/color/hsl-lighten.d.ts → src/color/hsl-lighten.ts} +7 -2
- package/{dist/color/hsv-brighten.d.ts → src/color/hsv-brighten.ts} +7 -2
- package/{dist/color/luminance.d.ts → src/color/luminance.ts} +9 -2
- package/{dist/color/mix.d.ts → src/color/mix.ts} +10 -2
- package/src/color/rgb-hsl.ts +53 -0
- package/{dist/color/rgb-hsv.d.ts → src/color/rgb-hsv.ts} +30 -3
- package/src/color/rgb-hwb.ts +56 -0
- package/{dist/color/rgb-lab.d.ts → src/color/rgb-lab.ts} +11 -3
- package/src/color/rgb-whiter.ts +22 -0
- package/src/color/rgb-xyz.ts +62 -0
- package/{dist/color/types.d.ts → src/color/types.ts} +12 -30
- package/{dist/color/xyz-lab.d.ts → src/color/xyz-lab.ts} +32 -3
- package/src/crypto/md5.mjs +357 -0
- package/src/crypto/sha1.mjs +300 -0
- package/src/crypto/sha256.mjs +310 -0
- package/src/crypto/sha512.mjs +459 -0
- package/{dist/crypto.d.ts → src/crypto.ts} +20 -4
- package/src/date/const.ts +6 -0
- package/src/date/core.ts +162 -0
- package/src/date/days.ts +51 -0
- package/{dist/date/is.d.ts → src/date/is.ts} +102 -8
- package/src/date/relative.ts +92 -0
- package/src/date/start-end.ts +246 -0
- package/src/date/timezone.ts +220 -0
- package/src/date/weeks.ts +100 -0
- package/src/dts/global.d.ts +27 -0
- package/src/easing.ts +166 -0
- package/src/emitter.ts +117 -0
- package/src/enum.ts +171 -0
- package/{dist/env.d.ts → src/env.ts} +30 -6
- package/{dist/error.d.ts → src/error.ts} +12 -3
- package/src/exception.ts +68 -0
- package/src/fn.ts +197 -0
- package/src/index.ts +1 -0
- package/src/number.ts +236 -0
- package/{dist/object/each.d.ts → src/object/each.ts} +23 -3
- package/src/object/get-set.ts +273 -0
- package/src/object/is.ts +128 -0
- package/src/object/merge.ts +180 -0
- package/{dist/object/process.d.ts → src/object/process.ts} +38 -4
- package/src/path.ts +188 -0
- package/{dist/promise.d.ts → src/promise.ts} +67 -6
- package/{dist/qs.d.ts → src/qs.ts} +60 -3
- package/src/regexp.ts +156 -0
- package/src/string.ts +146 -0
- package/src/time/from.ts +57 -0
- package/src/time/to.ts +106 -0
- package/{dist/timer.mjs → src/timer.ts} +124 -17
- package/{dist/tree.d.ts → src/tree.ts} +225 -41
- package/{dist/type.d.ts → src/type.ts} +96 -20
- package/{dist/types.d.ts → src/types.ts} +33 -12
- package/src/unique.ts +77 -0
- package/src/url.ts +93 -0
- package/src/version.ts +71 -0
- package/test/array.test.ts +332 -0
- package/test/async-real.test.ts +39 -0
- package/test/async.test.ts +375 -0
- package/test/base64.test.ts +32 -0
- package/test/cache.test.ts +83 -0
- package/test/color.test.ts +163 -0
- package/test/crypto.test.ts +34 -0
- package/test/date-tz.test.ts +206 -0
- package/test/date.test.ts +353 -0
- package/test/easing.test.ts +33 -0
- package/test/emitter.test.ts +71 -0
- package/test/enum.test.ts +113 -0
- package/test/env.test.ts +69 -0
- package/test/error.test.ts +58 -0
- package/test/exception.test.ts +43 -0
- package/test/fn.test.ts +263 -0
- package/test/helpers.ts +23 -0
- package/test/index.test.ts +6 -0
- package/test/number.test.ts +213 -0
- package/test/object.test.ts +309 -0
- package/test/path.test.ts +156 -0
- package/test/promise.test.ts +199 -0
- package/test/qs.test.ts +79 -0
- package/test/regexp.test.ts +97 -0
- package/test/string.test.ts +150 -0
- package/test/time.test.ts +214 -0
- package/test/timer.test.ts +114 -0
- package/test/tree.test.ts +348 -0
- package/test/type.test.ts +226 -0
- package/test/unique.test.ts +71 -0
- package/test/url.test.ts +136 -0
- package/test/version.test.ts +52 -0
- package/tsconfig.json +31 -0
- package/vite.config.mts +114 -0
- package/dist/array.cjs +0 -129
- package/dist/array.cjs.map +0 -1
- package/dist/array.d.ts +0 -171
- package/dist/array.mjs +0 -129
- package/dist/array.mjs.map +0 -1
- package/dist/async.cjs +0 -219
- package/dist/async.cjs.map +0 -1
- package/dist/async.d.ts +0 -137
- package/dist/async.mjs +0 -219
- package/dist/async.mjs.map +0 -1
- package/dist/base64.cjs +0 -16
- package/dist/base64.cjs.map +0 -1
- package/dist/base64.d.ts +0 -7
- package/dist/base64.mjs +0 -16
- package/dist/base64.mjs.map +0 -1
- package/dist/cache.cjs +0 -79
- package/dist/cache.cjs.map +0 -1
- package/dist/cache.d.ts +0 -90
- package/dist/cache.mjs +0 -79
- package/dist/cache.mjs.map +0 -1
- package/dist/color/distance.d.ts +0 -8
- package/dist/color/helpers.d.ts +0 -2
- package/dist/color/hex-hsl.d.ts +0 -3
- package/dist/color/hex-rgb.d.ts +0 -18
- package/dist/color/rgb-hsl.d.ts +0 -23
- package/dist/color/rgb-hwb.d.ts +0 -29
- package/dist/color/rgb-whiter.d.ts +0 -12
- package/dist/color/rgb-xyz.d.ts +0 -22
- package/dist/color.cjs +0 -250
- package/dist/color.cjs.map +0 -1
- package/dist/color.mjs +0 -250
- package/dist/color.mjs.map +0 -1
- package/dist/const.cjs +0 -14
- package/dist/const.cjs.map +0 -1
- package/dist/const.mjs +0 -15
- package/dist/const.mjs.map +0 -1
- package/dist/core.cjs +0 -250
- package/dist/core.cjs.map +0 -1
- package/dist/core.mjs +0 -251
- package/dist/core.mjs.map +0 -1
- package/dist/crypto/md5.d.mts +0 -1
- package/dist/crypto/sha1.d.mts +0 -1
- package/dist/crypto/sha256.d.mts +0 -1
- package/dist/crypto/sha512.d.mts +0 -1
- package/dist/crypto.cjs +0 -812
- package/dist/crypto.cjs.map +0 -1
- package/dist/crypto.mjs +0 -812
- package/dist/crypto.mjs.map +0 -1
- package/dist/date/const.d.ts +0 -6
- package/dist/date/core.d.ts +0 -52
- package/dist/date/days.d.ts +0 -23
- package/dist/date/relative.d.ts +0 -44
- package/dist/date/start-end.d.ts +0 -73
- package/dist/date/timezone.d.ts +0 -67
- package/dist/date/weeks.d.ts +0 -72
- package/dist/date.cjs +0 -239
- package/dist/date.cjs.map +0 -1
- package/dist/date.mjs +0 -241
- package/dist/date.mjs.map +0 -1
- package/dist/dict.cjs +0 -2
- package/dist/dict.cjs.map +0 -1
- package/dist/dict.mjs +0 -2
- package/dist/dict.mjs.map +0 -1
- package/dist/each.cjs +0 -18
- package/dist/each.cjs.map +0 -1
- package/dist/each.mjs +0 -19
- package/dist/each.mjs.map +0 -1
- package/dist/easing.cjs +0 -151
- package/dist/easing.cjs.map +0 -1
- package/dist/easing.d.ts +0 -46
- package/dist/easing.mjs +0 -151
- package/dist/easing.mjs.map +0 -1
- package/dist/emitter.cjs +0 -94
- package/dist/emitter.cjs.map +0 -1
- package/dist/emitter.d.ts +0 -68
- package/dist/emitter.mjs +0 -94
- package/dist/emitter.mjs.map +0 -1
- package/dist/enum.cjs +0 -58
- package/dist/enum.cjs.map +0 -1
- package/dist/enum.d.ts +0 -68
- package/dist/enum.mjs +0 -58
- package/dist/enum.mjs.map +0 -1
- package/dist/env.cjs +0 -28
- package/dist/env.cjs.map +0 -1
- package/dist/env.mjs +0 -28
- package/dist/env.mjs.map +0 -1
- package/dist/error.cjs +0 -12
- package/dist/error.cjs.map +0 -1
- package/dist/error.mjs +0 -12
- package/dist/error.mjs.map +0 -1
- package/dist/exception.cjs +0 -22
- package/dist/exception.cjs.map +0 -1
- package/dist/exception.d.ts +0 -31
- package/dist/exception.mjs +0 -22
- package/dist/exception.mjs.map +0 -1
- package/dist/fn.cjs +0 -76
- package/dist/fn.cjs.map +0 -1
- package/dist/fn.d.ts +0 -102
- package/dist/fn.mjs +0 -76
- package/dist/fn.mjs.map +0 -1
- package/dist/index.cjs +0 -5
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.mjs +0 -5
- package/dist/index.mjs.map +0 -1
- package/dist/merge.cjs +0 -87
- package/dist/merge.cjs.map +0 -1
- package/dist/merge.mjs +0 -88
- package/dist/merge.mjs.map +0 -1
- package/dist/number.cjs +0 -11
- package/dist/number.cjs.map +0 -1
- package/dist/number.d.ts +0 -137
- package/dist/number.mjs +0 -11
- package/dist/number.mjs.map +0 -1
- package/dist/object/get-set.d.ts +0 -111
- package/dist/object/is.d.ts +0 -32
- package/dist/object/merge.d.ts +0 -72
- package/dist/object.cjs +0 -130
- package/dist/object.cjs.map +0 -1
- package/dist/object.mjs +0 -130
- package/dist/object.mjs.map +0 -1
- package/dist/path.cjs +0 -77
- package/dist/path.cjs.map +0 -1
- package/dist/path.d.ts +0 -82
- package/dist/path.mjs +0 -77
- package/dist/path.mjs.map +0 -1
- package/dist/promise.cjs +0 -62
- package/dist/promise.cjs.map +0 -1
- package/dist/promise.mjs +0 -62
- package/dist/promise.mjs.map +0 -1
- package/dist/qs.cjs +0 -47
- package/dist/qs.cjs.map +0 -1
- package/dist/qs.mjs +0 -47
- package/dist/qs.mjs.map +0 -1
- package/dist/regexp.cjs +0 -66
- package/dist/regexp.cjs.map +0 -1
- package/dist/regexp.d.ts +0 -65
- package/dist/regexp.mjs +0 -66
- package/dist/regexp.mjs.map +0 -1
- package/dist/string.cjs +0 -16
- package/dist/string.cjs.map +0 -1
- package/dist/string.d.ts +0 -80
- package/dist/string.mjs +0 -16
- package/dist/string.mjs.map +0 -1
- package/dist/string2.cjs +0 -147
- package/dist/string2.cjs.map +0 -1
- package/dist/string2.mjs +0 -148
- package/dist/string2.mjs.map +0 -1
- package/dist/time/from.d.ts +0 -14
- package/dist/time/to.d.ts +0 -38
- package/dist/time.cjs +0 -82
- package/dist/time.cjs.map +0 -1
- package/dist/time.mjs +0 -82
- package/dist/time.mjs.map +0 -1
- package/dist/timer.cjs +0 -119
- package/dist/timer.cjs.map +0 -1
- package/dist/timer.d.ts +0 -96
- package/dist/timer.mjs.map +0 -1
- package/dist/tree.cjs +0 -125
- package/dist/tree.cjs.map +0 -1
- package/dist/tree.mjs +0 -125
- package/dist/tree.mjs.map +0 -1
- package/dist/type.cjs +0 -78
- package/dist/type.cjs.map +0 -1
- package/dist/type.mjs +0 -78
- package/dist/type.mjs.map +0 -1
- package/dist/types.cjs +0 -2
- package/dist/types.cjs.map +0 -1
- package/dist/types.mjs +0 -2
- package/dist/types.mjs.map +0 -1
- package/dist/unique.cjs +0 -46
- package/dist/unique.cjs.map +0 -1
- package/dist/unique.d.ts +0 -22
- package/dist/unique.mjs +0 -46
- package/dist/unique.mjs.map +0 -1
- package/dist/url.cjs +0 -37
- package/dist/url.cjs.map +0 -1
- package/dist/url.d.ts +0 -53
- package/dist/url.mjs +0 -37
- package/dist/url.mjs.map +0 -1
- package/dist/version.cjs +0 -33
- package/dist/version.cjs.map +0 -1
- package/dist/version.d.ts +0 -32
- package/dist/version.mjs +0 -33
- package/dist/version.mjs.map +0 -1
- /package/{dist/color.d.ts → src/color.ts} +0 -0
- /package/{dist/date.d.ts → src/date.ts} +0 -0
- /package/{dist/dict.d.ts → src/dict.ts} +0 -0
- /package/{dist/object.d.ts → src/object.ts} +0 -0
- /package/{dist/time.d.ts → src/time.ts} +0 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { isArray, isObject, typeIs } from '@/type';
|
|
2
|
+
import type { AnyArray, AnyObject } from '@/types';
|
|
3
|
+
import { objectEach } from './each';
|
|
4
|
+
|
|
5
|
+
export type TObjectMergeRule = {
|
|
6
|
+
/**
|
|
7
|
+
* 处理冲突
|
|
8
|
+
* @param target - 目标对象
|
|
9
|
+
* @param source - 源对象
|
|
10
|
+
* @param key - 键名
|
|
11
|
+
* @returns 返回 true 表示继续处理,否则返回 false
|
|
12
|
+
*/
|
|
13
|
+
next: (info: {
|
|
14
|
+
target: AnyObject | AnyArray;
|
|
15
|
+
source: AnyObject | AnyArray;
|
|
16
|
+
key: string | number;
|
|
17
|
+
}) => boolean;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 处理赋值
|
|
21
|
+
* @param target - 目标对象
|
|
22
|
+
* @param source - 源对象
|
|
23
|
+
* @param key - 键名
|
|
24
|
+
* @returns 返回处理后的值
|
|
25
|
+
*/
|
|
26
|
+
assign: (info: {
|
|
27
|
+
target: AnyObject | AnyArray;
|
|
28
|
+
source: AnyObject | AnyArray;
|
|
29
|
+
key: string | number;
|
|
30
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
31
|
+
merge: () => any;
|
|
32
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
33
|
+
}) => any;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function _objectMerge(mergeRule: TObjectMergeRule, target: AnyObject | AnyArray, ...sources: (AnyObject | AnyArray)[]) {
|
|
37
|
+
const seen = new WeakMap<AnyObject | AnyArray, AnyObject | AnyArray>();
|
|
38
|
+
const { assign, next } = mergeRule;
|
|
39
|
+
const align = (target: AnyObject | AnyArray, source: AnyObject | AnyArray) => {
|
|
40
|
+
const targetType = typeIs(target);
|
|
41
|
+
const sourceType = typeIs(source);
|
|
42
|
+
|
|
43
|
+
if (targetType === sourceType) {
|
|
44
|
+
return target;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return sourceType === 'array' ? [] : {};
|
|
48
|
+
};
|
|
49
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
50
|
+
const each = (source: AnyObject | AnyArray, iterator: (val: any, key: string | number) => void) => {
|
|
51
|
+
if (isObject(source)) {
|
|
52
|
+
objectEach(source, iterator);
|
|
53
|
+
} else {
|
|
54
|
+
source.forEach(iterator);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const merge = (target: AnyObject | AnyArray, source: AnyObject | AnyArray): AnyObject | AnyArray => {
|
|
59
|
+
// 如果循环引用了,则直接返回目标对象
|
|
60
|
+
if (seen.has(source)) {
|
|
61
|
+
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
62
|
+
return seen.get(source)!;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 对齐目标对象和源对象
|
|
66
|
+
const merged = align(target, source);
|
|
67
|
+
|
|
68
|
+
// 存储循环引用
|
|
69
|
+
seen.set(source, merged);
|
|
70
|
+
|
|
71
|
+
// 遍历源对象
|
|
72
|
+
each(source, (value, key) => {
|
|
73
|
+
if (!next({ target: merged, source, key })) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (isObject(value) || isArray(value)) {
|
|
78
|
+
// @ts-expect-error
|
|
79
|
+
merged[key] = assign({
|
|
80
|
+
target: merged,
|
|
81
|
+
source,
|
|
82
|
+
key,
|
|
83
|
+
// @ts-expect-error
|
|
84
|
+
merge: () => merge(merged[key], value),
|
|
85
|
+
});
|
|
86
|
+
} else {
|
|
87
|
+
// @ts-expect-error
|
|
88
|
+
merged[key] = assign({
|
|
89
|
+
target: merged,
|
|
90
|
+
source,
|
|
91
|
+
key,
|
|
92
|
+
merge: () => value,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return merged;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
let returnTarget = target;
|
|
101
|
+
|
|
102
|
+
for (const source of sources) {
|
|
103
|
+
returnTarget = merge(target, source);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return returnTarget;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 合并多个对象或数组。如果遇到循环引用,则直接返回目标对象。
|
|
111
|
+
*
|
|
112
|
+
* @param target - 目标对象或数组。
|
|
113
|
+
* @param sources - 要合并的源对象或数组。
|
|
114
|
+
* @returns 合并后的对象或数组。
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const obj1 = { a: 1, b: { x: 10 } };
|
|
119
|
+
* const obj2 = { b: { y: 20 }, c: 3 };
|
|
120
|
+
* const merged = objectMerge(obj1, obj2);
|
|
121
|
+
* console.log(merged); // { a: 1, b: { x: 10, y: 20 }, c: 3 }
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export function objectMerge(target: AnyObject | AnyArray, ...sources: (AnyObject | AnyArray)[]) {
|
|
125
|
+
return _objectMerge(
|
|
126
|
+
{
|
|
127
|
+
next() {
|
|
128
|
+
return true;
|
|
129
|
+
},
|
|
130
|
+
assign({ merge }) {
|
|
131
|
+
return merge();
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
target,
|
|
135
|
+
...sources,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 为对象设置默认值。如果目标对象中的属性为 `undefined`,则使用默认对象中的属性值。
|
|
141
|
+
* 支持多个默认对象,优先级从左到右依次降低。
|
|
142
|
+
* 如果目标对象中的属性已经是对象或数组,则递归地设置默认值。
|
|
143
|
+
*
|
|
144
|
+
* @param target - 目标对象或数组。
|
|
145
|
+
* @param defaults - 默认对象或数组。
|
|
146
|
+
* @returns 合并后的对象或数组。
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* const obj = { a: 1, b: undefined };
|
|
151
|
+
* const defaults = { a: 4, b: 2, c: 3 };
|
|
152
|
+
* const result = objectDefaults(obj, defaults);
|
|
153
|
+
* console.log(result); // { a: 1, b: 2, c: 3 }
|
|
154
|
+
*
|
|
155
|
+
* const obj2 = { a: 1, b: 2 };
|
|
156
|
+
* const defaults2 = { a: 5, b: 3, c: 4 };
|
|
157
|
+
* const result2 = objectDefaults(obj2, defaults2);
|
|
158
|
+
* console.log(result2); // { a: 1, b: 2, c: 4 }
|
|
159
|
+
*
|
|
160
|
+
* const obj3 = { a: { x: 1 }, b: undefined };
|
|
161
|
+
* const defaults3 = { a: { x: 4, z: 3 }, b: { y: 2 } };
|
|
162
|
+
* const result3 = objectDefaults(obj3, defaults3);
|
|
163
|
+
* console.log(result3); // { a: { x: 1, z: 3 }, b: { y: 2 } }
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export function objectDefaults<T extends AnyObject | AnyArray>(target: T, defaults: T): T {
|
|
167
|
+
return _objectMerge(
|
|
168
|
+
{
|
|
169
|
+
next({ target, source, key }) {
|
|
170
|
+
// @ts-expect-error
|
|
171
|
+
return target[key] === undefined || isObject(target[key]) || isArray(target[key]);
|
|
172
|
+
},
|
|
173
|
+
assign({ merge }) {
|
|
174
|
+
return merge();
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
target,
|
|
178
|
+
defaults,
|
|
179
|
+
) as T;
|
|
180
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { AnyObject } from '
|
|
1
|
+
import type { AnyObject } from '@/types';
|
|
2
|
+
|
|
2
3
|
/**
|
|
3
4
|
* 从对象中选择指定键的属性,返回一个新的对象。
|
|
4
5
|
*
|
|
@@ -13,7 +14,16 @@ import { AnyObject } from '../types';
|
|
|
13
14
|
* console.log(result); // { a: 1, c: 3 }
|
|
14
15
|
* ```
|
|
15
16
|
*/
|
|
16
|
-
export
|
|
17
|
+
export function objectPick<T extends AnyObject, K extends keyof T>(object: T, keys: K[]): Pick<T, K> {
|
|
18
|
+
const result = {} as Pick<T, K>;
|
|
19
|
+
for (const key of keys) {
|
|
20
|
+
if (key in object) {
|
|
21
|
+
result[key] = object[key];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
|
|
17
27
|
/**
|
|
18
28
|
* 从对象中排除指定键的属性,返回一个新的对象。
|
|
19
29
|
*
|
|
@@ -28,7 +38,17 @@ export declare function objectPick<T extends AnyObject, K extends keyof T>(objec
|
|
|
28
38
|
* console.log(result); // { b: 2, c: 3 }
|
|
29
39
|
* ```
|
|
30
40
|
*/
|
|
31
|
-
export
|
|
41
|
+
export function objectOmit<T extends AnyObject, K extends keyof T>(object: T, keys: K[]): Omit<T, K> {
|
|
42
|
+
const result = {} as Omit<T, K>;
|
|
43
|
+
for (const key in object) {
|
|
44
|
+
if (!keys.includes(key as unknown as K)) {
|
|
45
|
+
// @ts-expect-error
|
|
46
|
+
result[key] = object[key];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
32
52
|
/**
|
|
33
53
|
* 遍历对象的每个键值对,并对每个键值对执行提供的映射函数,返回一个新的对象。
|
|
34
54
|
*
|
|
@@ -43,4 +63,18 @@ export declare function objectOmit<T extends AnyObject, K extends keyof T>(objec
|
|
|
43
63
|
* console.log(result); // { a: '2', b: '4', c: '6' }
|
|
44
64
|
* ```
|
|
45
65
|
*/
|
|
46
|
-
export
|
|
66
|
+
export function objectMap<T extends AnyObject, V>(
|
|
67
|
+
object: T,
|
|
68
|
+
mapper: (value: T[keyof T], key: keyof T) => V,
|
|
69
|
+
): Record<keyof T, V> {
|
|
70
|
+
return Object.fromEntries(
|
|
71
|
+
Object.entries(object).map(([key, value]) => [
|
|
72
|
+
key,
|
|
73
|
+
mapper(
|
|
74
|
+
// @ts-expect-error
|
|
75
|
+
value,
|
|
76
|
+
key as keyof T,
|
|
77
|
+
),
|
|
78
|
+
]),
|
|
79
|
+
) as Record<keyof T, V>;
|
|
80
|
+
}
|
package/src/path.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { arrayEach } from './array';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 判断是否是当前目录标记
|
|
5
|
+
* @param {string} slice - 路径片段
|
|
6
|
+
* @returns {boolean} - 如果是当前目录标记'.'则返回true,否则返回false
|
|
7
|
+
*/
|
|
8
|
+
function _isCurrentSlice(slice: string): boolean {
|
|
9
|
+
return slice === '.';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 判断是否是上级目录标记
|
|
14
|
+
* @param {string} slice - 路径片段
|
|
15
|
+
* @returns {boolean} - 如果是上级目录标记'..'则返回true,否则返回false
|
|
16
|
+
*/
|
|
17
|
+
function _isParentSlice(slice: string): boolean {
|
|
18
|
+
return slice === '..';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 判断是否是绝对路径
|
|
23
|
+
* @param {string} path - 路径字符串
|
|
24
|
+
* @returns {boolean} - 如果是绝对路径则返回true,否则返回false
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const isAbs = isAbsolutePath('/path/to/file');
|
|
28
|
+
* console.log(isAbs); // 输出: true
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function isAbsolutePath(path: string): boolean {
|
|
32
|
+
return path.startsWith('/');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 判断是否是相对路径
|
|
37
|
+
* @param {string} path - 路径字符串
|
|
38
|
+
* @returns {boolean} - 如果是相对路径则返回true,否则返回false
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const isRel = isRelativePath('path/to/file');
|
|
42
|
+
* console.log(isRel); // 输出: true
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function isRelativePath(path: string): boolean {
|
|
46
|
+
return !isAbsolutePath(path);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 标准化路径
|
|
51
|
+
* @param {string} path - 要标准化的路径字符串。
|
|
52
|
+
* @returns {string} - 标准化后的路径字符串。
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const normalizedPath = pathNormalize('/path///to///file');
|
|
56
|
+
* console.log(normalizedPath); // 输出: '/path/to/file'
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function pathNormalize(path: string): string {
|
|
60
|
+
const slices = path
|
|
61
|
+
.replace(/\\/g, '/')
|
|
62
|
+
.replace(/\/{2,}/g, '/')
|
|
63
|
+
.replace(/\.{3,}/g, '..')
|
|
64
|
+
.replace(/\/\.\//g, '/')
|
|
65
|
+
.split('/')
|
|
66
|
+
.map((point) => point.trim());
|
|
67
|
+
const points: string[] = [];
|
|
68
|
+
const isAbs = slices[0] === '';
|
|
69
|
+
|
|
70
|
+
const push = (point: string) => {
|
|
71
|
+
points.push(point);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const back = () => {
|
|
75
|
+
// 绝对路径不能退到根目录
|
|
76
|
+
if (points.length === 1 && isAbs) return;
|
|
77
|
+
|
|
78
|
+
//
|
|
79
|
+
if (points.length === 0 || points.at(-1) === '..') {
|
|
80
|
+
points.push('..');
|
|
81
|
+
} else {
|
|
82
|
+
points.pop();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
for (const slice of slices) {
|
|
87
|
+
const isCurrent = _isCurrentSlice(slice);
|
|
88
|
+
const isParent = _isParentSlice(slice);
|
|
89
|
+
|
|
90
|
+
// // 未进入实际路径
|
|
91
|
+
// if (!inPoints) {
|
|
92
|
+
// push(slice);
|
|
93
|
+
// inPoints = !isCurrent && !isParent;
|
|
94
|
+
// continue;
|
|
95
|
+
// }
|
|
96
|
+
|
|
97
|
+
if (isCurrent) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (isParent) {
|
|
102
|
+
back();
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
push(slice);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return points.join('/');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 路径合并
|
|
114
|
+
* @param {string} from - 起始路径。
|
|
115
|
+
* @param {...string[]} to - 要合并的路径片段。
|
|
116
|
+
* @returns {string} - 合并后的路径字符串。
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* const fullPath = pathJoin('/path', '/to', 'file');
|
|
120
|
+
* console.log(fullPath); // 输出: '/path/to/file'
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export function pathJoin(from: string, ...to: string[]): string {
|
|
124
|
+
return pathNormalize([from, ...to].join('/'));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 解析路径
|
|
129
|
+
* @param {string} from - 起始路径
|
|
130
|
+
* @param {...string[]} to - 要解析的路径片段
|
|
131
|
+
* @returns {string} - 解析后的绝对路径
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* const resolvedPath = pathResolve('/path', '/to', 'file');
|
|
135
|
+
* console.log(resolvedPath); // 输出: '/to/file'
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export function pathResolve(from: string, ...to: string[]): string {
|
|
139
|
+
const paths = [from, ...to].map(pathNormalize);
|
|
140
|
+
|
|
141
|
+
let lastStartPath = from;
|
|
142
|
+
let lastStartIndex = 0;
|
|
143
|
+
|
|
144
|
+
arrayEach(
|
|
145
|
+
paths,
|
|
146
|
+
(path, index) => {
|
|
147
|
+
if (isAbsolutePath(path)) {
|
|
148
|
+
lastStartPath = path;
|
|
149
|
+
lastStartIndex = index;
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
true,
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
return pathJoin(lastStartPath, ...paths.slice(lastStartIndex + 1));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 将相对路径转换为标准的相对路径格式(添加'./'前缀)
|
|
161
|
+
*
|
|
162
|
+
* @param {string} path - 要处理的路径字符串
|
|
163
|
+
* @returns {string} 处理后的路径字符串
|
|
164
|
+
*
|
|
165
|
+
* @example <caption>处理绝对路径</caption>
|
|
166
|
+
* ```typescript
|
|
167
|
+
* const result = pathRelativize('/path/to/file');
|
|
168
|
+
* console.log(result); // 输出: '/path/to/file'
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @example <caption>处理已带'./'前缀的相对路径</caption>
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const result = pathRelativize('./path/to/file');
|
|
174
|
+
* console.log(result); // 输出: './path/to/file'
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* @example <caption>处理不带'./'前缀的相对路径</caption>
|
|
178
|
+
* ```typescript
|
|
179
|
+
* const result = pathRelativize('path/to/file');
|
|
180
|
+
* console.log(result); // 输出: './path/to/file'
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
export function pathRelativize(path: string): string {
|
|
184
|
+
if (isAbsolutePath(path)) return path;
|
|
185
|
+
if (path.startsWith('./')) return path;
|
|
186
|
+
if (path.startsWith('../')) return path;
|
|
187
|
+
return `./${path}`;
|
|
188
|
+
}
|
|
@@ -1,16 +1,33 @@
|
|
|
1
|
+
import { isObject, isPromise } from './type';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* 检查给定的值是否为 Promise 类似对象。
|
|
3
5
|
* @param unknown - 要检查的值。
|
|
4
6
|
* @returns 如果值是 Promise 类似对象,则返回 `true`,否则返回 `false`。
|
|
5
7
|
*/
|
|
6
|
-
export
|
|
8
|
+
export function isPromiseLike<T>(unknown: unknown): unknown is Promise<T> {
|
|
9
|
+
return isPromise(unknown) || (isObject(unknown) && typeof (unknown as unknown as Promise<T>).then === 'function');
|
|
10
|
+
}
|
|
11
|
+
|
|
7
12
|
/**
|
|
8
13
|
* 等待一定时间后解决 Promise
|
|
9
14
|
* @param ms - 等待的毫秒数,默认为 0
|
|
10
15
|
* @param ctrl - 可选的 AbortController,用于提前终止等待
|
|
11
16
|
* @returns 一个 Promise,等待指定时间后解决
|
|
12
17
|
*/
|
|
13
|
-
export
|
|
18
|
+
export async function promiseDelay(ms = 0, ctrl?: AbortController) {
|
|
19
|
+
return new Promise<void>((resolve) => {
|
|
20
|
+
const t = setTimeout(resolve, ms);
|
|
21
|
+
|
|
22
|
+
if (ctrl) {
|
|
23
|
+
ctrl.signal.addEventListener('abort', () => {
|
|
24
|
+
clearTimeout(t);
|
|
25
|
+
resolve();
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
14
31
|
/**
|
|
15
32
|
* 使 Promise 在指定时间内执行,超时则拒绝
|
|
16
33
|
* @param promise - 要执行的 Promise
|
|
@@ -18,14 +35,38 @@ export declare function promiseDelay(ms?: number, ctrl?: AbortController): Promi
|
|
|
18
35
|
* @returns 如果 Promise 在指定时间内解决,则返回其结果;否则抛出 "timeout" 错误
|
|
19
36
|
* @throws {Error} 如果 Promise 超时,抛出 "timeout" 错误
|
|
20
37
|
*/
|
|
21
|
-
export
|
|
38
|
+
export async function promiseTimeout<T>(promise: Promise<T>, ms: number) {
|
|
39
|
+
const ctrl = new AbortController();
|
|
40
|
+
const result = await Promise.race([
|
|
41
|
+
promise,
|
|
42
|
+
promiseDelay(ms, ctrl).then(() => {
|
|
43
|
+
throw new Error('timeout');
|
|
44
|
+
}),
|
|
45
|
+
]);
|
|
46
|
+
ctrl.abort();
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
22
50
|
/**
|
|
23
51
|
* 在指定条件满足时解决 Promise
|
|
24
52
|
* @param condition - 一个返回布尔值的函数,用于检查条件是否满足
|
|
25
53
|
* @param ms - 检查条件的时间间隔(毫秒),默认为 10
|
|
26
54
|
* @returns 一个 Promise,在条件满足时解决
|
|
27
55
|
*/
|
|
28
|
-
export
|
|
56
|
+
export function promiseWhen(condition: () => boolean, ms = 10) {
|
|
57
|
+
return new Promise<void>((resolve, reject) => {
|
|
58
|
+
const check = () => {
|
|
59
|
+
if (condition()) {
|
|
60
|
+
resolve();
|
|
61
|
+
} else {
|
|
62
|
+
setTimeout(check, ms);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
check();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
29
70
|
/**
|
|
30
71
|
* 创建一个与给定 Promise 共享状态的新 Promise。
|
|
31
72
|
* 新的 Promise 不具备 resolve 或 reject 的能力,它仅反映原始 Promise 的状态。
|
|
@@ -37,7 +78,12 @@ export declare function promiseWhen(condition: () => boolean, ms?: number): Prom
|
|
|
37
78
|
* const sp2 = sharedPromise(p1);
|
|
38
79
|
* // 此时 sp1、sp2 完全共享 p1 的状态,自身并不具备 resolve 或 reject 的能力
|
|
39
80
|
*/
|
|
40
|
-
export
|
|
81
|
+
export function promiseShared<T>(promise: Promise<T>) {
|
|
82
|
+
return new Promise<T>((resolve, reject) => {
|
|
83
|
+
promise.then(resolve, reject);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
41
87
|
/**
|
|
42
88
|
* 创建一个最小等待时间的函数
|
|
43
89
|
* @param {number} ms - 最小等待时间(毫秒)
|
|
@@ -47,4 +93,19 @@ export declare function promiseShared<T>(promise: Promise<T>): Promise<T>;
|
|
|
47
93
|
* // 执行一些操作
|
|
48
94
|
* await end(); // 确保从 createMinDelayPromise 调用到这里的总时间至少为 1000 毫秒
|
|
49
95
|
*/
|
|
50
|
-
export
|
|
96
|
+
export function createMinDelayPromise(ms: number) {
|
|
97
|
+
const startTime = Date.now();
|
|
98
|
+
/**
|
|
99
|
+
* 确保最小等待时间的结束函数
|
|
100
|
+
* @async
|
|
101
|
+
* @function end
|
|
102
|
+
* @returns {Promise<void>} 在达到最小等待时间后解决
|
|
103
|
+
*/
|
|
104
|
+
return async function end() {
|
|
105
|
+
const endTime = Date.now();
|
|
106
|
+
const waitTime = ms - (endTime - startTime);
|
|
107
|
+
if (waitTime > 0) {
|
|
108
|
+
await promiseDelay(waitTime);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { objectEach } from './object';
|
|
2
|
+
import { isArray, isBoolean, isDate, isNull, isNullish, isNumber, isString, isUndefined } from './type';
|
|
3
|
+
import type { AnyObject } from './types';
|
|
4
|
+
|
|
2
5
|
/**
|
|
3
6
|
* 查询字符串解析函数
|
|
4
7
|
* @template T - 解析后返回的对象类型
|
|
@@ -14,6 +17,7 @@ import { AnyObject } from './types';
|
|
|
14
17
|
* };
|
|
15
18
|
*/
|
|
16
19
|
export type QSReader<T extends AnyObject> = (value: string, key: string, qsObject: T) => unknown;
|
|
20
|
+
|
|
17
21
|
/**
|
|
18
22
|
* 解析查询字符串为对象
|
|
19
23
|
* @template T - 返回的对象类型
|
|
@@ -30,7 +34,30 @@ export type QSReader<T extends AnyObject> = (value: string, key: string, qsObjec
|
|
|
30
34
|
* });
|
|
31
35
|
* // { date: Date('2023-01-01') }
|
|
32
36
|
*/
|
|
33
|
-
export
|
|
37
|
+
export function qsParse<T extends AnyObject>(queryString: string, parser?: QSReader<T>): T {
|
|
38
|
+
// 添加 globalThis 是便于对接外部环境 URL 的自行实现
|
|
39
|
+
// 例如在 uni-app、微信小程序等运行环境。
|
|
40
|
+
const sp = new globalThis.URLSearchParams(queryString.replace(/^.*\?/, ''));
|
|
41
|
+
const qsObject = {} as T;
|
|
42
|
+
|
|
43
|
+
for (const [key, val] of sp.entries()) {
|
|
44
|
+
const valFinal = parser ? parser(val, key, qsObject) : val;
|
|
45
|
+
|
|
46
|
+
if (isNullish(valFinal)) continue;
|
|
47
|
+
|
|
48
|
+
if (Object.hasOwn(qsObject, key)) {
|
|
49
|
+
// @ts-expect-error
|
|
50
|
+
if (!isArray(qsObject[key])) qsObject[key] = [qsObject[key]];
|
|
51
|
+
(qsObject[key] as unknown[]).push(val);
|
|
52
|
+
} else {
|
|
53
|
+
// @ts-expect-error
|
|
54
|
+
qsObject[key] = valFinal;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return qsObject;
|
|
59
|
+
}
|
|
60
|
+
|
|
34
61
|
/**
|
|
35
62
|
* 查询字符串序列化函数
|
|
36
63
|
* @template T - 要序列化的对象类型
|
|
@@ -46,6 +73,14 @@ export declare function qsParse<T extends AnyObject>(queryString: string, parser
|
|
|
46
73
|
* };
|
|
47
74
|
*/
|
|
48
75
|
export type QSWriter<T extends AnyObject = AnyObject> = (value: unknown, key: string, query: T) => string | null;
|
|
76
|
+
const defaultWriter: QSWriter<AnyObject> = (val: unknown) => {
|
|
77
|
+
if (isString(val)) return val;
|
|
78
|
+
if (isNumber(val)) return String(val);
|
|
79
|
+
if (isBoolean(val)) return val ? 'true' : 'false';
|
|
80
|
+
if (isDate(val)) return val.toISOString();
|
|
81
|
+
return null;
|
|
82
|
+
};
|
|
83
|
+
|
|
49
84
|
/**
|
|
50
85
|
* 将对象序列化为查询字符串
|
|
51
86
|
* @template T - 要序列化的对象类型
|
|
@@ -59,4 +94,26 @@ export type QSWriter<T extends AnyObject = AnyObject> = (value: unknown, key: st
|
|
|
59
94
|
* const str2 = qsStringify({ date: new Date('2023-01-01') });
|
|
60
95
|
* // 'date=2023-01-01T00:00:00.000Z'
|
|
61
96
|
*/
|
|
62
|
-
export
|
|
97
|
+
export function qsStringify<T extends AnyObject>(qsObject: T, stringify: QSWriter<T> = defaultWriter): string {
|
|
98
|
+
// 添加 globalThis 是便于对接外部环境 URL 的自行实现
|
|
99
|
+
// 例如在 uni-app、微信小程序等运行环境。
|
|
100
|
+
const sp = new globalThis.URLSearchParams();
|
|
101
|
+
const pushPairs = (val: unknown, key: string) => {
|
|
102
|
+
const valFinal = stringify(val, String(key), qsObject);
|
|
103
|
+
if (isNullish(valFinal)) return;
|
|
104
|
+
|
|
105
|
+
sp.append(key, valFinal);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
objectEach(qsObject, (val, key: string) => {
|
|
109
|
+
if (isArray(val)) {
|
|
110
|
+
for (const it of val) {
|
|
111
|
+
pushPairs(it, key);
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
pushPairs(val, key);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return sp.toString();
|
|
119
|
+
}
|