@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.
Files changed (292) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +21 -0
  3. package/package.json +279 -1
  4. package/src/array.ts +312 -0
  5. package/src/async.ts +379 -0
  6. package/src/base64.ts +20 -0
  7. package/src/cache.ts +146 -0
  8. package/{dist/color/contrast.d.ts → src/color/contrast.ts} +12 -2
  9. package/src/color/distance.ts +28 -0
  10. package/src/color/helpers.ts +23 -0
  11. package/src/color/hex-hsl.ts +11 -0
  12. package/{dist/color/hex-hsv.d.ts → src/color/hex-hsv.ts} +11 -3
  13. package/{dist/color/hex-hwb.d.ts → src/color/hex-hwb.ts} +11 -3
  14. package/src/color/hex-rgb.ts +39 -0
  15. package/{dist/color/hsl-lighten.d.ts → src/color/hsl-lighten.ts} +7 -2
  16. package/{dist/color/hsv-brighten.d.ts → src/color/hsv-brighten.ts} +7 -2
  17. package/{dist/color/luminance.d.ts → src/color/luminance.ts} +9 -2
  18. package/{dist/color/mix.d.ts → src/color/mix.ts} +10 -2
  19. package/src/color/rgb-hsl.ts +53 -0
  20. package/{dist/color/rgb-hsv.d.ts → src/color/rgb-hsv.ts} +30 -3
  21. package/src/color/rgb-hwb.ts +56 -0
  22. package/{dist/color/rgb-lab.d.ts → src/color/rgb-lab.ts} +11 -3
  23. package/src/color/rgb-whiter.ts +22 -0
  24. package/src/color/rgb-xyz.ts +62 -0
  25. package/{dist/color/types.d.ts → src/color/types.ts} +12 -30
  26. package/{dist/color/xyz-lab.d.ts → src/color/xyz-lab.ts} +32 -3
  27. package/src/crypto/md5.mjs +357 -0
  28. package/src/crypto/sha1.mjs +300 -0
  29. package/src/crypto/sha256.mjs +310 -0
  30. package/src/crypto/sha512.mjs +459 -0
  31. package/{dist/crypto.d.ts → src/crypto.ts} +20 -4
  32. package/src/date/const.ts +6 -0
  33. package/src/date/core.ts +162 -0
  34. package/src/date/days.ts +51 -0
  35. package/{dist/date/is.d.ts → src/date/is.ts} +102 -8
  36. package/src/date/relative.ts +92 -0
  37. package/src/date/start-end.ts +246 -0
  38. package/src/date/timezone.ts +220 -0
  39. package/src/date/weeks.ts +100 -0
  40. package/src/dts/global.d.ts +27 -0
  41. package/src/easing.ts +166 -0
  42. package/src/emitter.ts +117 -0
  43. package/src/enum.ts +171 -0
  44. package/{dist/env.d.ts → src/env.ts} +30 -6
  45. package/{dist/error.d.ts → src/error.ts} +12 -3
  46. package/src/exception.ts +68 -0
  47. package/src/fn.ts +197 -0
  48. package/src/index.ts +1 -0
  49. package/src/number.ts +236 -0
  50. package/{dist/object/each.d.ts → src/object/each.ts} +23 -3
  51. package/src/object/get-set.ts +273 -0
  52. package/src/object/is.ts +128 -0
  53. package/src/object/merge.ts +180 -0
  54. package/{dist/object/process.d.ts → src/object/process.ts} +38 -4
  55. package/src/path.ts +188 -0
  56. package/{dist/promise.d.ts → src/promise.ts} +67 -6
  57. package/{dist/qs.d.ts → src/qs.ts} +60 -3
  58. package/src/regexp.ts +156 -0
  59. package/src/string.ts +146 -0
  60. package/src/time/from.ts +57 -0
  61. package/src/time/to.ts +106 -0
  62. package/{dist/timer.mjs → src/timer.ts} +124 -17
  63. package/{dist/tree.d.ts → src/tree.ts} +225 -41
  64. package/{dist/type.d.ts → src/type.ts} +96 -20
  65. package/{dist/types.d.ts → src/types.ts} +33 -12
  66. package/src/unique.ts +77 -0
  67. package/src/url.ts +93 -0
  68. package/src/version.ts +71 -0
  69. package/test/array.test.ts +332 -0
  70. package/test/async-real.test.ts +39 -0
  71. package/test/async.test.ts +375 -0
  72. package/test/base64.test.ts +32 -0
  73. package/test/cache.test.ts +83 -0
  74. package/test/color.test.ts +163 -0
  75. package/test/crypto.test.ts +34 -0
  76. package/test/date-tz.test.ts +206 -0
  77. package/test/date.test.ts +353 -0
  78. package/test/easing.test.ts +33 -0
  79. package/test/emitter.test.ts +71 -0
  80. package/test/enum.test.ts +113 -0
  81. package/test/env.test.ts +69 -0
  82. package/test/error.test.ts +58 -0
  83. package/test/exception.test.ts +43 -0
  84. package/test/fn.test.ts +263 -0
  85. package/test/helpers.ts +23 -0
  86. package/test/index.test.ts +6 -0
  87. package/test/number.test.ts +213 -0
  88. package/test/object.test.ts +309 -0
  89. package/test/path.test.ts +156 -0
  90. package/test/promise.test.ts +199 -0
  91. package/test/qs.test.ts +79 -0
  92. package/test/regexp.test.ts +97 -0
  93. package/test/string.test.ts +150 -0
  94. package/test/time.test.ts +214 -0
  95. package/test/timer.test.ts +114 -0
  96. package/test/tree.test.ts +348 -0
  97. package/test/type.test.ts +226 -0
  98. package/test/unique.test.ts +71 -0
  99. package/test/url.test.ts +136 -0
  100. package/test/version.test.ts +52 -0
  101. package/tsconfig.json +31 -0
  102. package/vite.config.mts +114 -0
  103. package/dist/array.cjs +0 -129
  104. package/dist/array.cjs.map +0 -1
  105. package/dist/array.d.ts +0 -171
  106. package/dist/array.mjs +0 -129
  107. package/dist/array.mjs.map +0 -1
  108. package/dist/async.cjs +0 -219
  109. package/dist/async.cjs.map +0 -1
  110. package/dist/async.d.ts +0 -137
  111. package/dist/async.mjs +0 -219
  112. package/dist/async.mjs.map +0 -1
  113. package/dist/base64.cjs +0 -16
  114. package/dist/base64.cjs.map +0 -1
  115. package/dist/base64.d.ts +0 -7
  116. package/dist/base64.mjs +0 -16
  117. package/dist/base64.mjs.map +0 -1
  118. package/dist/cache.cjs +0 -79
  119. package/dist/cache.cjs.map +0 -1
  120. package/dist/cache.d.ts +0 -90
  121. package/dist/cache.mjs +0 -79
  122. package/dist/cache.mjs.map +0 -1
  123. package/dist/color/distance.d.ts +0 -8
  124. package/dist/color/helpers.d.ts +0 -2
  125. package/dist/color/hex-hsl.d.ts +0 -3
  126. package/dist/color/hex-rgb.d.ts +0 -18
  127. package/dist/color/rgb-hsl.d.ts +0 -23
  128. package/dist/color/rgb-hwb.d.ts +0 -29
  129. package/dist/color/rgb-whiter.d.ts +0 -12
  130. package/dist/color/rgb-xyz.d.ts +0 -22
  131. package/dist/color.cjs +0 -250
  132. package/dist/color.cjs.map +0 -1
  133. package/dist/color.mjs +0 -250
  134. package/dist/color.mjs.map +0 -1
  135. package/dist/const.cjs +0 -14
  136. package/dist/const.cjs.map +0 -1
  137. package/dist/const.mjs +0 -15
  138. package/dist/const.mjs.map +0 -1
  139. package/dist/core.cjs +0 -250
  140. package/dist/core.cjs.map +0 -1
  141. package/dist/core.mjs +0 -251
  142. package/dist/core.mjs.map +0 -1
  143. package/dist/crypto/md5.d.mts +0 -1
  144. package/dist/crypto/sha1.d.mts +0 -1
  145. package/dist/crypto/sha256.d.mts +0 -1
  146. package/dist/crypto/sha512.d.mts +0 -1
  147. package/dist/crypto.cjs +0 -812
  148. package/dist/crypto.cjs.map +0 -1
  149. package/dist/crypto.mjs +0 -812
  150. package/dist/crypto.mjs.map +0 -1
  151. package/dist/date/const.d.ts +0 -6
  152. package/dist/date/core.d.ts +0 -52
  153. package/dist/date/days.d.ts +0 -23
  154. package/dist/date/relative.d.ts +0 -44
  155. package/dist/date/start-end.d.ts +0 -73
  156. package/dist/date/timezone.d.ts +0 -67
  157. package/dist/date/weeks.d.ts +0 -72
  158. package/dist/date.cjs +0 -239
  159. package/dist/date.cjs.map +0 -1
  160. package/dist/date.mjs +0 -241
  161. package/dist/date.mjs.map +0 -1
  162. package/dist/dict.cjs +0 -2
  163. package/dist/dict.cjs.map +0 -1
  164. package/dist/dict.mjs +0 -2
  165. package/dist/dict.mjs.map +0 -1
  166. package/dist/each.cjs +0 -18
  167. package/dist/each.cjs.map +0 -1
  168. package/dist/each.mjs +0 -19
  169. package/dist/each.mjs.map +0 -1
  170. package/dist/easing.cjs +0 -151
  171. package/dist/easing.cjs.map +0 -1
  172. package/dist/easing.d.ts +0 -46
  173. package/dist/easing.mjs +0 -151
  174. package/dist/easing.mjs.map +0 -1
  175. package/dist/emitter.cjs +0 -94
  176. package/dist/emitter.cjs.map +0 -1
  177. package/dist/emitter.d.ts +0 -68
  178. package/dist/emitter.mjs +0 -94
  179. package/dist/emitter.mjs.map +0 -1
  180. package/dist/enum.cjs +0 -58
  181. package/dist/enum.cjs.map +0 -1
  182. package/dist/enum.d.ts +0 -68
  183. package/dist/enum.mjs +0 -58
  184. package/dist/enum.mjs.map +0 -1
  185. package/dist/env.cjs +0 -28
  186. package/dist/env.cjs.map +0 -1
  187. package/dist/env.mjs +0 -28
  188. package/dist/env.mjs.map +0 -1
  189. package/dist/error.cjs +0 -12
  190. package/dist/error.cjs.map +0 -1
  191. package/dist/error.mjs +0 -12
  192. package/dist/error.mjs.map +0 -1
  193. package/dist/exception.cjs +0 -22
  194. package/dist/exception.cjs.map +0 -1
  195. package/dist/exception.d.ts +0 -31
  196. package/dist/exception.mjs +0 -22
  197. package/dist/exception.mjs.map +0 -1
  198. package/dist/fn.cjs +0 -76
  199. package/dist/fn.cjs.map +0 -1
  200. package/dist/fn.d.ts +0 -102
  201. package/dist/fn.mjs +0 -76
  202. package/dist/fn.mjs.map +0 -1
  203. package/dist/index.cjs +0 -5
  204. package/dist/index.cjs.map +0 -1
  205. package/dist/index.d.ts +0 -1
  206. package/dist/index.mjs +0 -5
  207. package/dist/index.mjs.map +0 -1
  208. package/dist/merge.cjs +0 -87
  209. package/dist/merge.cjs.map +0 -1
  210. package/dist/merge.mjs +0 -88
  211. package/dist/merge.mjs.map +0 -1
  212. package/dist/number.cjs +0 -11
  213. package/dist/number.cjs.map +0 -1
  214. package/dist/number.d.ts +0 -137
  215. package/dist/number.mjs +0 -11
  216. package/dist/number.mjs.map +0 -1
  217. package/dist/object/get-set.d.ts +0 -111
  218. package/dist/object/is.d.ts +0 -32
  219. package/dist/object/merge.d.ts +0 -72
  220. package/dist/object.cjs +0 -130
  221. package/dist/object.cjs.map +0 -1
  222. package/dist/object.mjs +0 -130
  223. package/dist/object.mjs.map +0 -1
  224. package/dist/path.cjs +0 -77
  225. package/dist/path.cjs.map +0 -1
  226. package/dist/path.d.ts +0 -82
  227. package/dist/path.mjs +0 -77
  228. package/dist/path.mjs.map +0 -1
  229. package/dist/promise.cjs +0 -62
  230. package/dist/promise.cjs.map +0 -1
  231. package/dist/promise.mjs +0 -62
  232. package/dist/promise.mjs.map +0 -1
  233. package/dist/qs.cjs +0 -47
  234. package/dist/qs.cjs.map +0 -1
  235. package/dist/qs.mjs +0 -47
  236. package/dist/qs.mjs.map +0 -1
  237. package/dist/regexp.cjs +0 -66
  238. package/dist/regexp.cjs.map +0 -1
  239. package/dist/regexp.d.ts +0 -65
  240. package/dist/regexp.mjs +0 -66
  241. package/dist/regexp.mjs.map +0 -1
  242. package/dist/string.cjs +0 -16
  243. package/dist/string.cjs.map +0 -1
  244. package/dist/string.d.ts +0 -80
  245. package/dist/string.mjs +0 -16
  246. package/dist/string.mjs.map +0 -1
  247. package/dist/string2.cjs +0 -147
  248. package/dist/string2.cjs.map +0 -1
  249. package/dist/string2.mjs +0 -148
  250. package/dist/string2.mjs.map +0 -1
  251. package/dist/time/from.d.ts +0 -14
  252. package/dist/time/to.d.ts +0 -38
  253. package/dist/time.cjs +0 -82
  254. package/dist/time.cjs.map +0 -1
  255. package/dist/time.mjs +0 -82
  256. package/dist/time.mjs.map +0 -1
  257. package/dist/timer.cjs +0 -119
  258. package/dist/timer.cjs.map +0 -1
  259. package/dist/timer.d.ts +0 -96
  260. package/dist/timer.mjs.map +0 -1
  261. package/dist/tree.cjs +0 -125
  262. package/dist/tree.cjs.map +0 -1
  263. package/dist/tree.mjs +0 -125
  264. package/dist/tree.mjs.map +0 -1
  265. package/dist/type.cjs +0 -78
  266. package/dist/type.cjs.map +0 -1
  267. package/dist/type.mjs +0 -78
  268. package/dist/type.mjs.map +0 -1
  269. package/dist/types.cjs +0 -2
  270. package/dist/types.cjs.map +0 -1
  271. package/dist/types.mjs +0 -2
  272. package/dist/types.mjs.map +0 -1
  273. package/dist/unique.cjs +0 -46
  274. package/dist/unique.cjs.map +0 -1
  275. package/dist/unique.d.ts +0 -22
  276. package/dist/unique.mjs +0 -46
  277. package/dist/unique.mjs.map +0 -1
  278. package/dist/url.cjs +0 -37
  279. package/dist/url.cjs.map +0 -1
  280. package/dist/url.d.ts +0 -53
  281. package/dist/url.mjs +0 -37
  282. package/dist/url.mjs.map +0 -1
  283. package/dist/version.cjs +0 -33
  284. package/dist/version.cjs.map +0 -1
  285. package/dist/version.d.ts +0 -32
  286. package/dist/version.mjs +0 -33
  287. package/dist/version.mjs.map +0 -1
  288. /package/{dist/color.d.ts → src/color.ts} +0 -0
  289. /package/{dist/date.d.ts → src/date.ts} +0 -0
  290. /package/{dist/dict.d.ts → src/dict.ts} +0 -0
  291. /package/{dist/object.d.ts → src/object.ts} +0 -0
  292. /package/{dist/time.d.ts → src/time.ts} +0 -0
package/src/enum.ts ADDED
@@ -0,0 +1,171 @@
1
+ import type { AnyObject, MergeIntersection, UnionToIntersection, UnionToTuple } from './types';
2
+
3
+ export type EnumKey = string;
4
+ export type EnumValue = number | string;
5
+ export type EnumMetaAppend = {
6
+ key?: string;
7
+ value?: string | number;
8
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
9
+ [key: string]: any;
10
+ };
11
+ export type EnumMeta<A extends EnumMetaAppend> = A & {
12
+ value: EnumValue;
13
+ };
14
+ export type EnumDescription<A extends EnumMetaAppend> = Record<EnumKey, EnumMeta<A>>;
15
+
16
+ const enumError = Symbol('enumKeyError');
17
+
18
+ type _StartWithDollarSign<T extends string> = T extends `$${infer R}` ? R : never;
19
+
20
+ type _CheckDefinition<O extends AnyObject> = {
21
+ // [K in keyof O & string]: K extends Capitalize<K> ? O[K] : `错误:枚举键名 ${K} 必须大写字母开头`;
22
+ [K in keyof O & string]: K extends Capitalize<K>
23
+ ? K extends `$${infer R}`
24
+ ? O[K] & { [enumError]: `错误:枚举键名 ${K} 不能以 $ 符号开头` }
25
+ : O[K]
26
+ : O[K] & { [enumError]: `错误:枚举键名 ${K} 必须以大写字母开头` };
27
+ };
28
+
29
+ type _ToOriginDefProp<T extends AnyObject> = {
30
+ [K in keyof T as `$${K & string}`]: MergeIntersection<T[K] & { readonly key: K }>;
31
+ };
32
+
33
+ type _KVRecord<T> = T extends Record<string, AnyObject>
34
+ ? {
35
+ readonly [K in keyof T]: T[K]['value'];
36
+ }
37
+ : never;
38
+
39
+ type _VKRecord<T> = T extends Record<string, AnyObject>
40
+ ? MergeIntersection<
41
+ UnionToIntersection<
42
+ {
43
+ [K in keyof T]: {
44
+ [P in keyof T[K] as P extends 'value' ? T[K][P] & (string | number) : never]: K;
45
+ };
46
+ }[keyof T]
47
+ >
48
+ >
49
+ : never;
50
+
51
+ export type EnumExpose<A extends EnumMetaAppend, E extends EnumDescription<A>> = _ToOriginDefProp<E> &
52
+ _KVRecord<E> & {
53
+ readonly definition: E;
54
+ readonly descriptions: MergeIntersection<A & { key: keyof E }>[];
55
+ readonly keys: UnionToTuple<keyof E>;
56
+ readonly length: UnionToTuple<keyof E>['length'];
57
+ readonly values: UnionToTuple<E[keyof E]['value']>;
58
+ readonly kvRecord: _KVRecord<E>;
59
+ readonly vkRecord: _VKRecord<E>;
60
+ toKeyRecord: <P extends keyof A>(prop: P) => Record<keyof E, A[P]>;
61
+ toValueRecord: <P extends keyof A>(prop: P) => Record<E[keyof E]['value'], A[P]>;
62
+ };
63
+
64
+ /**
65
+ * 定义一个枚举类型,如果需要类型提示,需要使用 declareEnum 函数定义枚举。
66
+ * @template A - 枚举元数据附加类型,扩展自 EnumMetaAppend
67
+ * @template E - 枚举描述类型,键为枚举键名,值为枚举元数据
68
+ * @param {_CheckDefinition<E>} definition - 枚举定义对象
69
+ * @returns {EnumExpose<A, E>} 返回枚举的完整暴露对象
70
+ * @example
71
+ * ```typescript
72
+ * const Status = defineEnum({
73
+ * Pending: { value: 0, label: '待处理' },
74
+ * Approved: { value: 1, label: '已批准' }
75
+ * });
76
+ * ```
77
+ *
78
+ * @property {E} definition - 原始枚举定义对象
79
+ * @property {Array<MergeIntersection<A & { key: keyof E }>>} descriptions - 枚举项的完整描述数组
80
+ * @property {UnionToTuple<keyof E>} keys - 枚举键名的元组
81
+ * @property {"UnionToTuple<keyof E>[\"length\"]"} length - 枚举项的数量
82
+ * @property {UnionToTuple<E[keyof E]["value"]>} values - 枚举值的元组
83
+ * @property {Record<keyof E, E[keyof E]["value"]>} kvRecord - 键到值的映射记录
84
+ * @property {Record<E[keyof E]["value"], E[keyof E]>} vkRecord - 值到键的映射记录
85
+ * @property {function} toKeyRecord - 根据属性名创建键到属性值的映射记录
86
+ * @property {function} toValueRecord - 根据属性名创建值到属性值的映射记录
87
+ */
88
+ function defineEnum<A extends EnumMetaAppend, const E extends EnumDescription<A>>(
89
+ definition: _CheckDefinition<E>,
90
+ ): EnumExpose<A, E> {
91
+ const keys = Object.keys(definition);
92
+
93
+ return {
94
+ ...[...Object.entries(definition)].reduce((acc, [key, dfn]) => {
95
+ if (key[0].toUpperCase() !== key[0]) {
96
+ throw new Error(`错误:枚举键名 ${key} 必须以大写字母开头`);
97
+ }
98
+
99
+ if (key.startsWith('$')) {
100
+ throw new Error(`错误:枚举键名 ${key} 不能以 $ 符号开头`);
101
+ }
102
+
103
+ // @ts-ignore
104
+ acc[key] = dfn.value;
105
+ // @ts-ignore
106
+ acc[`$${key}`] = { key, ...dfn };
107
+ return acc;
108
+ }, {}),
109
+ definition,
110
+ descriptions: keys.map((key) => ({
111
+ key,
112
+ ...definition[key],
113
+ })),
114
+ keys,
115
+ length: keys.length,
116
+ values: keys.map((key) => definition[key as keyof E].value),
117
+ kvRecord: keys.reduce((acc, key) => {
118
+ // @ts-ignore
119
+ acc[key] = definition[key].value;
120
+ return acc;
121
+ }, {}),
122
+ vkRecord: keys.reduce((acc, key) => {
123
+ // @ts-ignore
124
+ acc[definition[key].value] = key;
125
+ return acc;
126
+ }, {}),
127
+ toKeyRecord<P extends keyof A>(prop: P) {
128
+ return keys.reduce((acc, key) => {
129
+ // @ts-ignore
130
+ acc[key] = definition[key][prop];
131
+ return acc;
132
+ }, {});
133
+ },
134
+ toValueRecord<P extends keyof A>(prop: P) {
135
+ return keys.reduce(
136
+ (acc, key) => {
137
+ // @ts-ignore
138
+ acc[definition[key].value] = definition[key][prop];
139
+ return acc;
140
+ },
141
+ {} as Record<E[keyof E]['value'], A[P]>,
142
+ );
143
+ },
144
+ } as unknown as EnumExpose<A, E>;
145
+ }
146
+
147
+ /**
148
+ * 声明一个枚举工厂函数
149
+ * @template A - 枚举元数据附加类型,扩展自 EnumMetaAppend
150
+ * @returns {Object} 返回包含 define 方法的对象
151
+ *
152
+ * @property {function} define - 定义枚举的函数
153
+ * @template E - 枚举描述类型
154
+ * @param {_CheckDefinition<E>} definition - 枚举定义对象
155
+ * @returns {EnumExpose<A, E>} 返回枚举的完整暴露对象
156
+ * @example
157
+ * ```typescript
158
+ * const createStatusEnum = declareEnum<{ label: string }>();
159
+ * const Status = createStatusEnum.define({
160
+ * Pending: { value: 0, label: '待处理' },
161
+ * Approved: { value: 1, label: '已批准' }
162
+ * });
163
+ * ```
164
+ */
165
+ export function declareEnum<A extends EnumMetaAppend>() {
166
+ return {
167
+ define<const E extends EnumDescription<A>>(definition: _CheckDefinition<E>): EnumExpose<A, E> {
168
+ return defineEnum(definition);
169
+ },
170
+ };
171
+ }
@@ -1,38 +1,62 @@
1
+ import { isNullish } from './type';
2
+
1
3
  /**
2
4
  * 判断当前环境是否为浏览器环境
3
5
  * @returns 如果是浏览器环境返回 true,否则返回 false
4
6
  */
5
- export declare function isBrowser(): boolean;
7
+ export function isBrowser() {
8
+ if (IS_TEST) return TEST_MOCK.IS_BROWSER || false;
9
+
10
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
11
+ }
12
+
6
13
  /**
7
14
  * 判断当前环境是否为 Node.js 环境
8
15
  * @returns 如果是 Node.js 环境返回 true,否则返回 false
9
16
  */
10
- export declare function isNode(): boolean;
17
+ export function isNode() {
18
+ if (IS_TEST) return TEST_MOCK.IS_NODE || false;
19
+
20
+ return typeof process !== 'undefined' && !isNullish(process.versions) && !isNullish(process.versions.node);
21
+ }
22
+
11
23
  /**
12
24
  * 判断当前环境是否为 Web Worker 环境
13
25
  * @returns 如果是 Web Worker 环境返回 true,否则返回 false
14
26
  * @remarks
15
27
  * 使用 @ts-ignore 忽略 self 的类型检查,因为 self 在 Web Worker 中可用但在其他环境中可能未定义
16
28
  */
17
- export declare function isWorker(): boolean;
29
+ export function isWorker() {
30
+ // @ts-ignore
31
+ return typeof self !== 'undefined' && self.importScripts != null;
32
+ }
33
+
18
34
  /**
19
35
  * 判断当前操作系统是否为 macOS
20
36
  * @returns 如果是 macOS 返回 true,否则返回 false
21
37
  * @remarks
22
38
  * 在浏览器环境中通过 navigator.platform 检测,在 Node.js 环境中通过 process.platform 检测
23
39
  */
24
- export declare function isMacOS(): boolean;
40
+ export function isMacOS() {
41
+ return isBrowser() ? /^mac/i.test(navigator.platform) : isNode() ? /^darwin/i.test(process.platform) : false;
42
+ }
43
+
25
44
  /**
26
45
  * 判断当前操作系统是否为 Linux
27
46
  * @returns 如果是 Linux 返回 true,否则返回 false
28
47
  * @remarks
29
48
  * 在浏览器环境中通过 navigator.platform 检测,在 Node.js 环境中通过 process.platform 检测
30
49
  */
31
- export declare function isLinux(): boolean;
50
+ export function isLinux() {
51
+ return isBrowser() ? /^linux/i.test(navigator.platform) : isNode() ? /^linux/i.test(process.platform) : false;
52
+ }
53
+
32
54
  /**
33
55
  * 判断当前操作系统是否为 Windows
34
56
  * @returns 如果是 Windows 返回 true,否则返回 false
35
57
  * @remarks
36
58
  * 在浏览器环境中通过 navigator.platform 检测,在 Node.js 环境中通过 process.platform 检测
37
59
  */
38
- export declare function isWindows(): boolean;
60
+ export function isWindows() {
61
+ return isBrowser() ? /^win/i.test(navigator.platform) : isNode() ? /^win/i.test(process.platform) : false;
62
+ }
@@ -1,4 +1,6 @@
1
- import { AnyObject } from './types';
1
+ import { isError, isNullish } from './type';
2
+ import type { AnyObject } from './types';
3
+
2
4
  /**
3
5
  * 标准化处理 Error 对象,适用于 try-catch
4
6
  * @param throwError 接收抛出的错误字符串或者 Error 对象或字符串
@@ -7,7 +9,12 @@ import { AnyObject } from './types';
7
9
  * const error = errorNormalize('这是一个错误');
8
10
  * console.log(error.message); // 输出: 这是一个错误
9
11
  */
10
- export declare function errorNormalize<E extends Error | unknown = unknown>(throwError: E): E extends Error ? E : Error;
12
+ export function errorNormalize<E extends Error | unknown = unknown>(throwError: E) {
13
+ return (
14
+ isError(throwError) ? throwError : new Error(String(isNullish(throwError) ? '' : throwError))
15
+ ) as E extends Error ? E : Error;
16
+ }
17
+
11
18
  /**
12
19
  * 分配对象到 Error 对象上,适用于扩展 Error 实例,不影响原型和构造函数
13
20
  * @param {Error} error
@@ -19,4 +26,6 @@ export declare function errorNormalize<E extends Error | unknown = unknown>(thro
19
26
  * console.log(extendedError.code); // 输出: 404
20
27
  * console.log(extendedError.message); // 输出: 未找到资源
21
28
  */
22
- export declare function errorAssign<E extends AnyObject>(error: Error, source: E): Error & E;
29
+ export function errorAssign<E extends AnyObject>(error: Error, source: E): Error & E {
30
+ return Object.assign(error, source) as Error & E;
31
+ }
@@ -0,0 +1,68 @@
1
+ import { objectDefaults } from './object';
2
+ import type { AnyObject } from './types';
3
+
4
+ /**
5
+ * 构建异常选项
6
+ */
7
+ export type BuildExceptionOptions = {
8
+ /**
9
+ * 自定义错误消息格式函数
10
+ * @param name 错误名称
11
+ * @param message 原始错误消息
12
+ * @returns 格式化后的错误消息
13
+ * @example
14
+ * (name, message) => `${name}::${message}`
15
+ */
16
+ format?: (name: string, message: string) => string;
17
+ };
18
+
19
+ /**
20
+ * 默认的异常构建选项
21
+ */
22
+ const defaults: BuildExceptionOptions = {
23
+ /**
24
+ * 默认消息格式函数
25
+ * @default (name, message) => `[${name}] ${message}`
26
+ */
27
+ format: (name, message) => `[${name}] ${message}`,
28
+ };
29
+
30
+ /**
31
+ * 构建自定义异常类
32
+ * @template T 额外属性的类型
33
+ * @param name 异常类名称
34
+ * @param options 构建选项
35
+ * @returns 自定义异常类
36
+ * @example
37
+ * const MyException = buildException<{ code: number }>('MyException');
38
+ * const err = new MyException('error', { code: 404 });
39
+ *
40
+ * @example
41
+ * const SimpleException = buildException('SimpleException');
42
+ * const err = new SimpleException('error', undefined);
43
+ */
44
+ export function buildException<T = void>(name: string, options?: BuildExceptionOptions) {
45
+ const { format } = objectDefaults(options || {}, defaults) as Required<BuildExceptionOptions>;
46
+
47
+ return class extends Error {
48
+ constructor(message: string, extra: T) {
49
+ super(format(name, message));
50
+ this.name = name;
51
+ Object.assign(this, extra);
52
+ }
53
+ } as unknown as {
54
+ new (message: string, extra: T): Error & T;
55
+ };
56
+ }
57
+
58
+ // const MyException = buildException<{ foo: string; bar: number }>('MyException: ');
59
+ // const myException = new MyException('bar', { foo: '1', bar: 1 });
60
+ // myException.foo;
61
+ // myException.bar;
62
+ // myException.name;
63
+ // myException.message;
64
+ // myException.stack;
65
+ // myException.cause;
66
+
67
+ // const MyException2 = buildException('MyException2: ');
68
+ // const myException2 = new MyException2('bar');
package/src/fn.ts ADDED
@@ -0,0 +1,197 @@
1
+ import { isNumber } from './type';
2
+ import type { AnyFunction } from './types';
3
+
4
+ /**
5
+ * 一个空操作函数,不执行任何操作。
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * fnNoop(); // 不执行任何操作
10
+ * ```
11
+ */
12
+ export function fnNoop() {
13
+ //
14
+ }
15
+
16
+ /**
17
+ * 防抖函数的配置选项。
18
+ */
19
+ export type TDebounceOptions = {
20
+ /**
21
+ * 等待时间(毫秒)。
22
+ */
23
+ wait: number;
24
+ /**
25
+ * 是否在等待开始时立即执行一次
26
+ * @default false
27
+ */
28
+ leading?: boolean;
29
+ };
30
+
31
+ /**
32
+ * 创建一个防抖函数,该函数会在指定的等待时间后执行,如果在等待时间内再次调用,则重新计时。
33
+ *
34
+ * @param fn - 需要防抖的函数。
35
+ * @param wait - 等待时间(毫秒)或包含 `wait` 和 `leading` 选项的对象。
36
+ * @returns 返回一个防抖函数,该函数具有 `cancel` 方法,用于取消防抖操作。
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const debouncedFn = fnDebounce(() => {
41
+ * console.log('Debounced!');
42
+ * }, 100);
43
+ *
44
+ * debouncedFn(); // 不会立即执行
45
+ * debouncedFn(); // 重新计时
46
+ * debouncedFn.cancel(); // 取消防抖操作
47
+ * ```
48
+ */
49
+ export function fnDebounce<F extends AnyFunction>(fn: F, wait: number | TDebounceOptions) {
50
+ const options: TDebounceOptions = isNumber(wait) ? { wait } : wait;
51
+ let canceled = false;
52
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
53
+ let timer: any;
54
+ let leading = false;
55
+
56
+ const debounced = function (this: unknown, ...args: Parameters<F>) {
57
+ if (canceled) return;
58
+
59
+ // 第一次执行
60
+ if (options.leading && !leading) {
61
+ leading = true;
62
+ fn.apply(this, args);
63
+ return;
64
+ }
65
+
66
+ // 最后一次执行
67
+ clearTimeout(timer);
68
+ timer = setTimeout(() => {
69
+ if (canceled) return;
70
+
71
+ fn.apply(this, args);
72
+ }, options.wait);
73
+ };
74
+
75
+ debounced.cancel = () => {
76
+ clearTimeout(timer);
77
+ canceled = true;
78
+ };
79
+
80
+ return debounced;
81
+ }
82
+
83
+ export type TThrottleOptions = {
84
+ /**
85
+ * 等待时间(毫秒)。
86
+ */
87
+ wait: number;
88
+
89
+ /**
90
+ * 是否在第一次调用时立即执行
91
+ * @default false
92
+ */
93
+ leading?: boolean;
94
+
95
+ /**
96
+ * 是否在调用结束后等待一段时间再执行
97
+ * @default false
98
+ */
99
+ trailing?: boolean;
100
+ };
101
+
102
+ /**
103
+ * 创建一个节流函数,该函数会在指定的等待时间内最多执行一次,如果在等待时间内再次调用,则忽略后续调用。
104
+ *
105
+ * @param fn - 需要节流的函数。
106
+ * @param wait - 等待时间(毫秒)或包含 `wait`、`leading` 和 `trailing` 选项的对象。
107
+ * @returns 返回一个节流函数,该函数具有 `cancel` 方法,用于取消节流操作。
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * const throttledFn = fnThrottle(() => {
112
+ * console.log('Throttled!');
113
+ * }, 100);
114
+ *
115
+ * throttledFn(); // 立即执行
116
+ * throttledFn(); // 忽略
117
+ * throttledFn.cancel(); // 取消节流操作
118
+ * ```
119
+ */
120
+ export function fnThrottle<F extends AnyFunction>(fn: F, wait: number | TThrottleOptions) {
121
+ const options = isNumber(wait) ? { wait } : wait;
122
+ const waitFinal = options.wait;
123
+ let lastTime = 0;
124
+ let canceled = false;
125
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
126
+ let timer: any;
127
+
128
+ const throttled = function (this: unknown, ...args: Parameters<F>) {
129
+ if (canceled) return;
130
+
131
+ const now = Date.now();
132
+
133
+ // 第一次执行
134
+ if (options.leading && lastTime === 0) {
135
+ lastTime = now;
136
+ fn.apply(this, args);
137
+ }
138
+
139
+ // 中间控频执行
140
+ else if (lastTime > 0 && now - lastTime >= waitFinal) {
141
+ lastTime = now;
142
+ fn.apply(this, args);
143
+ }
144
+
145
+ // 首次计时
146
+ else if (lastTime === 0) {
147
+ lastTime = now;
148
+ }
149
+
150
+ // 最后一次执行
151
+ if (options.trailing) {
152
+ clearTimeout(timer);
153
+ timer = setTimeout(() => {
154
+ fn.apply(this, args);
155
+ }, waitFinal);
156
+ }
157
+ };
158
+
159
+ throttled.cancel = () => {
160
+ canceled = true;
161
+ clearTimeout(timer);
162
+ };
163
+
164
+ return throttled;
165
+ }
166
+
167
+ /**
168
+ * 创建一个只执行一次的函数,无论调用多少次,实际执行的函数体也只会执行一次。
169
+ *
170
+ * @param fn - 需要只执行一次的函数。
171
+ * @returns 返回一个只执行一次的函数,该函数在第一次调用后会缓存结果并返回缓存的结果。
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * const onceFn = fnOnce(() => {
176
+ * console.log('This will be logged only once.');
177
+ * return 42;
178
+ * });
179
+ *
180
+ * console.log(onceFn()); // 输出: This will be logged only once. 42
181
+ * console.log(onceFn()); // 输出: 42
182
+ * ```
183
+ */
184
+ export function fnOnce<F extends AnyFunction>(fn: F) {
185
+ let called = false;
186
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
187
+ let result: any;
188
+
189
+ return function (this: unknown, ...args: Parameters<F>) {
190
+ if (!called) {
191
+ called = true;
192
+ result = fn.apply(this, args);
193
+ }
194
+
195
+ return result;
196
+ };
197
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export const VERSION = PKG_VERSION;