@cloudcome/utils-core 1.8.0 → 1.9.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/dist/emitter.cjs CHANGED
@@ -1,18 +1,7 @@
1
1
  "use strict";
2
- var __typeError = (msg) => {
3
- throw TypeError(msg);
4
- };
5
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
6
- var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
7
- var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
8
- var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
9
- var _events, _Emitter_instances, offAll_fn, offEvent_fn, offListener_fn;
10
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
11
3
  class Emitter {
12
- constructor() {
13
- __privateAdd(this, _Emitter_instances);
14
- __privateAdd(this, _events, /* @__PURE__ */ new Map());
15
- }
4
+ #events = /* @__PURE__ */ new Map();
16
5
  /**
17
6
  * 注册事件监听器
18
7
  * @param event - 要监听的事件名称
@@ -23,11 +12,11 @@ class Emitter {
23
12
  * });
24
13
  */
25
14
  on(event, listener) {
26
- const listeners = __privateGet(this, _events).get(event);
15
+ const listeners = this.#events.get(event);
27
16
  if (listeners) {
28
17
  listeners.add(listener);
29
18
  } else {
30
- __privateGet(this, _events).set(event, /* @__PURE__ */ new Set([listener]));
19
+ this.#events.set(event, /* @__PURE__ */ new Set([listener]));
31
20
  }
32
21
  }
33
22
  /**
@@ -49,11 +38,23 @@ class Emitter {
49
38
  */
50
39
  off(event, listener) {
51
40
  if (event && listener) {
52
- __privateMethod(this, _Emitter_instances, offListener_fn).call(this, event, listener);
41
+ this.#offListener(event, listener);
53
42
  } else if (event) {
54
- __privateMethod(this, _Emitter_instances, offEvent_fn).call(this, event);
43
+ this.#offEvent(event);
55
44
  } else {
56
- __privateMethod(this, _Emitter_instances, offAll_fn).call(this);
45
+ this.#offAll();
46
+ }
47
+ }
48
+ #offAll() {
49
+ this.#events.clear();
50
+ }
51
+ #offEvent(event) {
52
+ this.#events.delete(event);
53
+ }
54
+ #offListener(event, listener) {
55
+ const listeners = this.#events.get(event);
56
+ if (listeners) {
57
+ listeners.delete(listener);
57
58
  }
58
59
  }
59
60
  /**
@@ -67,7 +68,7 @@ class Emitter {
67
68
  * emitter.emit('click', 10, 20);
68
69
  */
69
70
  emit(event, ...payloads) {
70
- const listeners = __privateGet(this, _events).get(event);
71
+ const listeners = this.#events.get(event);
71
72
  if (!listeners) return;
72
73
  for (const listener of [...listeners]) {
73
74
  if (listener(...payloads) === false) {
@@ -76,19 +77,5 @@ class Emitter {
76
77
  }
77
78
  }
78
79
  }
79
- _events = new WeakMap();
80
- _Emitter_instances = new WeakSet();
81
- offAll_fn = function() {
82
- __privateGet(this, _events).clear();
83
- };
84
- offEvent_fn = function(event) {
85
- __privateGet(this, _events).delete(event);
86
- };
87
- offListener_fn = function(event, listener) {
88
- const listeners = __privateGet(this, _events).get(event);
89
- if (listeners) {
90
- listeners.delete(listener);
91
- }
92
- };
93
80
  exports.Emitter = Emitter;
94
81
  //# sourceMappingURL=emitter.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"emitter.cjs","sources":["../src/emitter.ts"],"sourcesContent":["import type { AnyFunction, AnyObject } from './types';\n\n/**\n * 事件类型映射,key 为事件名称,value 为事件参数类型数组\n */\nexport type EmitterMap = Record<string, unknown[]>;\n\n/**\n * 事件监听器函数类型\n * @template E - EmitterMap 类型\n * @template K - 事件名称类型\n */\nexport type EmitterListener<E extends EmitterMap, K extends keyof E> = (...payloads: E[K]) => false | unknown;\n\n/**\n * 事件发射器类,用于管理事件监听和触发\n * @template E - 事件类型映射\n *\n * @example\n * type MyEvents = {\n * 'click': [x: number, y: number];\n * 'change': [value: string];\n * };\n *\n * const emitter = new Emitter<MyEvents>();\n * emitter.on('click', (x, y) => {\n * console.log(`Clicked at (${x}, ${y})`);\n * });\n * emitter.emit('click', 10, 20);\n */\nexport class Emitter<E extends EmitterMap> {\n #events: Map<keyof E, Set<AnyFunction>> = new Map();\n\n /**\n * 注册事件监听器\n * @param event - 要监听的事件名称\n * @param listener - 事件监听器函数\n * @example\n * emitter.on('click', (x, y) => {\n * console.log(`Clicked at (${x}, ${y})`);\n * });\n */\n on<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {\n const listeners = this.#events.get(event);\n if (listeners) {\n listeners.add(listener);\n } else {\n this.#events.set(event, new Set([listener]));\n }\n }\n\n /**\n * 移除事件监听器,有三种使用方式:\n * 1. 移除特定事件的特定监听器\n * 2. 移除特定事件的所有监听器\n * 3. 移除所有事件的所有监听器\n * @param event - 要移除的事件名称(可选)\n * @param listener - 要移除的监听器函数(可选)\n * @example\n * // 移除特定事件的特定监听器\n * emitter.off('click', clickHandler);\n *\n * // 移除特定事件的所有监听器\n * emitter.off('click');\n *\n * // 移除所有事件的所有监听器\n * emitter.off();\n */\n off<K extends keyof E>(event?: K, listener?: EmitterListener<E, K>) {\n if (event && listener) {\n this.#offListener(event, listener);\n } else if (event) {\n this.#offEvent(event);\n } else {\n this.#offAll();\n }\n }\n\n #offAll() {\n this.#events.clear();\n }\n\n #offEvent<K extends keyof E>(event: K) {\n this.#events.delete(event);\n }\n\n #offListener<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {\n const listeners = this.#events.get(event);\n\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * 触发指定事件,调用所有注册的监听器\n * @param event - 要触发的事件名称\n * @param payloads - 传递给监听器的参数\n * @remarks\n * 监听器会按照注册的顺序依次执行,如果某个监听器返回 false,\n * 则后续监听器将不会被执行\n * @example\n * emitter.emit('click', 10, 20);\n */\n emit<K extends keyof E>(event: K, ...payloads: Parameters<EmitterListener<E, K>>) {\n const listeners = this.#events.get(event) as Set<EmitterListener<E, K>> | undefined;\n\n if (!listeners) return;\n\n // 避免在 emit、on 的过程中改变 listeners 从而影响本次 emit\n for (const listener of [...listeners]) {\n if (listener(...payloads) === false) {\n break;\n }\n }\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;AA8BO,MAAM,QAA8B;AAAA,EAApC;AAAA;AACL,oDAA8C,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWlD,GAAsB,OAAU,UAAiC;AAC/D,UAAM,YAAY,mBAAK,SAAQ,IAAI,KAAK;AACxC,QAAI,WAAW;AACb,gBAAU,IAAI,QAAQ;AAAA,IAAA,OACjB;AACA,yBAAA,SAAQ,IAAI,OAAO,oBAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;AAAA,IAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBF,IAAuB,OAAW,UAAkC;AAClE,QAAI,SAAS,UAAU;AAChB,4BAAA,oCAAA,WAAa,OAAO;AAAA,eAChB,OAAO;AAChB,4BAAK,iCAAL,WAAe;AAAA,IAAK,OACf;AACL,4BAAK,+BAAL;AAAA,IAAa;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BF,KAAwB,UAAa,UAA6C;AAChF,UAAM,YAAY,mBAAK,SAAQ,IAAI,KAAK;AAExC,QAAI,CAAC,UAAW;AAGhB,eAAW,YAAY,CAAC,GAAG,SAAS,GAAG;AACrC,UAAI,SAAS,GAAG,QAAQ,MAAM,OAAO;AACnC;AAAA,MAAA;AAAA,IACF;AAAA,EACF;AAEJ;AArFE;AADK;AAgDL,YAAU,WAAA;AACR,qBAAK,SAAQ,MAAM;AAAA;AAGrB,uBAA6B,OAAU;AAChC,qBAAA,SAAQ,OAAO,KAAK;AAAA;AAG3B,iBAAA,SAAgC,OAAU,UAAiC;AACzE,QAAM,YAAY,mBAAK,SAAQ,IAAI,KAAK;AAExC,MAAI,WAAW;AACb,cAAU,OAAO,QAAQ;AAAA,EAAA;AAC3B;;"}
1
+ {"version":3,"file":"emitter.cjs","sources":["../src/emitter.ts"],"sourcesContent":["import type { AnyFunction, AnyObject } from './types';\n\n/**\n * 事件类型映射,key 为事件名称,value 为事件参数类型数组\n */\nexport type EmitterMap = Record<string, unknown[]>;\n\n/**\n * 事件监听器函数类型\n * @template E - EmitterMap 类型\n * @template K - 事件名称类型\n */\nexport type EmitterListener<E extends EmitterMap, K extends keyof E> = (...payloads: E[K]) => false | unknown;\n\n/**\n * 事件发射器类,用于管理事件监听和触发\n * @template E - 事件类型映射\n *\n * @example\n * type MyEvents = {\n * 'click': [x: number, y: number];\n * 'change': [value: string];\n * };\n *\n * const emitter = new Emitter<MyEvents>();\n * emitter.on('click', (x, y) => {\n * console.log(`Clicked at (${x}, ${y})`);\n * });\n * emitter.emit('click', 10, 20);\n */\nexport class Emitter<E extends EmitterMap> {\n #events: Map<keyof E, Set<AnyFunction>> = new Map();\n\n /**\n * 注册事件监听器\n * @param event - 要监听的事件名称\n * @param listener - 事件监听器函数\n * @example\n * emitter.on('click', (x, y) => {\n * console.log(`Clicked at (${x}, ${y})`);\n * });\n */\n on<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {\n const listeners = this.#events.get(event);\n if (listeners) {\n listeners.add(listener);\n } else {\n this.#events.set(event, new Set([listener]));\n }\n }\n\n /**\n * 移除事件监听器,有三种使用方式:\n * 1. 移除特定事件的特定监听器\n * 2. 移除特定事件的所有监听器\n * 3. 移除所有事件的所有监听器\n * @param event - 要移除的事件名称(可选)\n * @param listener - 要移除的监听器函数(可选)\n * @example\n * // 移除特定事件的特定监听器\n * emitter.off('click', clickHandler);\n *\n * // 移除特定事件的所有监听器\n * emitter.off('click');\n *\n * // 移除所有事件的所有监听器\n * emitter.off();\n */\n off<K extends keyof E>(event?: K, listener?: EmitterListener<E, K>) {\n if (event && listener) {\n this.#offListener(event, listener);\n } else if (event) {\n this.#offEvent(event);\n } else {\n this.#offAll();\n }\n }\n\n #offAll() {\n this.#events.clear();\n }\n\n #offEvent<K extends keyof E>(event: K) {\n this.#events.delete(event);\n }\n\n #offListener<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {\n const listeners = this.#events.get(event);\n\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * 触发指定事件,调用所有注册的监听器\n * @param event - 要触发的事件名称\n * @param payloads - 传递给监听器的参数\n * @remarks\n * 监听器会按照注册的顺序依次执行,如果某个监听器返回 false,\n * 则后续监听器将不会被执行\n * @example\n * emitter.emit('click', 10, 20);\n */\n emit<K extends keyof E>(event: K, ...payloads: Parameters<EmitterListener<E, K>>) {\n const listeners = this.#events.get(event) as Set<EmitterListener<E, K>> | undefined;\n\n if (!listeners) return;\n\n // 避免在 emit、on 的过程中改变 listeners 从而影响本次 emit\n for (const listener of [...listeners]) {\n if (listener(...payloads) === false) {\n break;\n }\n }\n }\n}\n"],"names":[],"mappings":";;AA8BO,MAAM,QAA8B;AAAA,EACzC,8BAA8C,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWlD,GAAsB,OAAU,UAAiC;AAC/D,UAAM,YAAY,KAAK,QAAQ,IAAI,KAAK;AACxC,QAAI,WAAW;AACb,gBAAU,IAAI,QAAQ;AAAA,IAAA,OACjB;AACA,WAAA,QAAQ,IAAI,OAAO,oBAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;AAAA,IAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBF,IAAuB,OAAW,UAAkC;AAClE,QAAI,SAAS,UAAU;AAChB,WAAA,aAAa,OAAO,QAAQ;AAAA,eACxB,OAAO;AAChB,WAAK,UAAU,KAAK;AAAA,IAAA,OACf;AACL,WAAK,QAAQ;AAAA,IAAA;AAAA,EACf;AAAA,EAGF,UAAU;AACR,SAAK,QAAQ,MAAM;AAAA,EAAA;AAAA,EAGrB,UAA6B,OAAU;AAChC,SAAA,QAAQ,OAAO,KAAK;AAAA,EAAA;AAAA,EAG3B,aAAgC,OAAU,UAAiC;AACzE,UAAM,YAAY,KAAK,QAAQ,IAAI,KAAK;AAExC,QAAI,WAAW;AACb,gBAAU,OAAO,QAAQ;AAAA,IAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF,KAAwB,UAAa,UAA6C;AAChF,UAAM,YAAY,KAAK,QAAQ,IAAI,KAAK;AAExC,QAAI,CAAC,UAAW;AAGhB,eAAW,YAAY,CAAC,GAAG,SAAS,GAAG;AACrC,UAAI,SAAS,GAAG,QAAQ,MAAM,OAAO;AACnC;AAAA,MAAA;AAAA,IACF;AAAA,EACF;AAEJ;;"}
package/dist/emitter.mjs CHANGED
@@ -1,16 +1,5 @@
1
- var __typeError = (msg) => {
2
- throw TypeError(msg);
3
- };
4
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
- var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
- var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
- var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
8
- var _events, _Emitter_instances, offAll_fn, offEvent_fn, offListener_fn;
9
1
  class Emitter {
10
- constructor() {
11
- __privateAdd(this, _Emitter_instances);
12
- __privateAdd(this, _events, /* @__PURE__ */ new Map());
13
- }
2
+ #events = /* @__PURE__ */ new Map();
14
3
  /**
15
4
  * 注册事件监听器
16
5
  * @param event - 要监听的事件名称
@@ -21,11 +10,11 @@ class Emitter {
21
10
  * });
22
11
  */
23
12
  on(event, listener) {
24
- const listeners = __privateGet(this, _events).get(event);
13
+ const listeners = this.#events.get(event);
25
14
  if (listeners) {
26
15
  listeners.add(listener);
27
16
  } else {
28
- __privateGet(this, _events).set(event, /* @__PURE__ */ new Set([listener]));
17
+ this.#events.set(event, /* @__PURE__ */ new Set([listener]));
29
18
  }
30
19
  }
31
20
  /**
@@ -47,11 +36,23 @@ class Emitter {
47
36
  */
48
37
  off(event, listener) {
49
38
  if (event && listener) {
50
- __privateMethod(this, _Emitter_instances, offListener_fn).call(this, event, listener);
39
+ this.#offListener(event, listener);
51
40
  } else if (event) {
52
- __privateMethod(this, _Emitter_instances, offEvent_fn).call(this, event);
41
+ this.#offEvent(event);
53
42
  } else {
54
- __privateMethod(this, _Emitter_instances, offAll_fn).call(this);
43
+ this.#offAll();
44
+ }
45
+ }
46
+ #offAll() {
47
+ this.#events.clear();
48
+ }
49
+ #offEvent(event) {
50
+ this.#events.delete(event);
51
+ }
52
+ #offListener(event, listener) {
53
+ const listeners = this.#events.get(event);
54
+ if (listeners) {
55
+ listeners.delete(listener);
55
56
  }
56
57
  }
57
58
  /**
@@ -65,7 +66,7 @@ class Emitter {
65
66
  * emitter.emit('click', 10, 20);
66
67
  */
67
68
  emit(event, ...payloads) {
68
- const listeners = __privateGet(this, _events).get(event);
69
+ const listeners = this.#events.get(event);
69
70
  if (!listeners) return;
70
71
  for (const listener of [...listeners]) {
71
72
  if (listener(...payloads) === false) {
@@ -74,20 +75,6 @@ class Emitter {
74
75
  }
75
76
  }
76
77
  }
77
- _events = new WeakMap();
78
- _Emitter_instances = new WeakSet();
79
- offAll_fn = function() {
80
- __privateGet(this, _events).clear();
81
- };
82
- offEvent_fn = function(event) {
83
- __privateGet(this, _events).delete(event);
84
- };
85
- offListener_fn = function(event, listener) {
86
- const listeners = __privateGet(this, _events).get(event);
87
- if (listeners) {
88
- listeners.delete(listener);
89
- }
90
- };
91
78
  export {
92
79
  Emitter
93
80
  };
@@ -1 +1 @@
1
- {"version":3,"file":"emitter.mjs","sources":["../src/emitter.ts"],"sourcesContent":["import type { AnyFunction, AnyObject } from './types';\n\n/**\n * 事件类型映射,key 为事件名称,value 为事件参数类型数组\n */\nexport type EmitterMap = Record<string, unknown[]>;\n\n/**\n * 事件监听器函数类型\n * @template E - EmitterMap 类型\n * @template K - 事件名称类型\n */\nexport type EmitterListener<E extends EmitterMap, K extends keyof E> = (...payloads: E[K]) => false | unknown;\n\n/**\n * 事件发射器类,用于管理事件监听和触发\n * @template E - 事件类型映射\n *\n * @example\n * type MyEvents = {\n * 'click': [x: number, y: number];\n * 'change': [value: string];\n * };\n *\n * const emitter = new Emitter<MyEvents>();\n * emitter.on('click', (x, y) => {\n * console.log(`Clicked at (${x}, ${y})`);\n * });\n * emitter.emit('click', 10, 20);\n */\nexport class Emitter<E extends EmitterMap> {\n #events: Map<keyof E, Set<AnyFunction>> = new Map();\n\n /**\n * 注册事件监听器\n * @param event - 要监听的事件名称\n * @param listener - 事件监听器函数\n * @example\n * emitter.on('click', (x, y) => {\n * console.log(`Clicked at (${x}, ${y})`);\n * });\n */\n on<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {\n const listeners = this.#events.get(event);\n if (listeners) {\n listeners.add(listener);\n } else {\n this.#events.set(event, new Set([listener]));\n }\n }\n\n /**\n * 移除事件监听器,有三种使用方式:\n * 1. 移除特定事件的特定监听器\n * 2. 移除特定事件的所有监听器\n * 3. 移除所有事件的所有监听器\n * @param event - 要移除的事件名称(可选)\n * @param listener - 要移除的监听器函数(可选)\n * @example\n * // 移除特定事件的特定监听器\n * emitter.off('click', clickHandler);\n *\n * // 移除特定事件的所有监听器\n * emitter.off('click');\n *\n * // 移除所有事件的所有监听器\n * emitter.off();\n */\n off<K extends keyof E>(event?: K, listener?: EmitterListener<E, K>) {\n if (event && listener) {\n this.#offListener(event, listener);\n } else if (event) {\n this.#offEvent(event);\n } else {\n this.#offAll();\n }\n }\n\n #offAll() {\n this.#events.clear();\n }\n\n #offEvent<K extends keyof E>(event: K) {\n this.#events.delete(event);\n }\n\n #offListener<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {\n const listeners = this.#events.get(event);\n\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * 触发指定事件,调用所有注册的监听器\n * @param event - 要触发的事件名称\n * @param payloads - 传递给监听器的参数\n * @remarks\n * 监听器会按照注册的顺序依次执行,如果某个监听器返回 false,\n * 则后续监听器将不会被执行\n * @example\n * emitter.emit('click', 10, 20);\n */\n emit<K extends keyof E>(event: K, ...payloads: Parameters<EmitterListener<E, K>>) {\n const listeners = this.#events.get(event) as Set<EmitterListener<E, K>> | undefined;\n\n if (!listeners) return;\n\n // 避免在 emit、on 的过程中改变 listeners 从而影响本次 emit\n for (const listener of [...listeners]) {\n if (listener(...payloads) === false) {\n break;\n }\n }\n }\n}\n"],"names":[],"mappings":";;;;;;;AA8BO;AAAA,MAAM,QAA8B;AAAA,EAApC;AAAA;AACL,oDAA8C,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWlD,GAAsB,OAAU,UAAiC;AAC/D,UAAM,YAAY,mBAAK,SAAQ,IAAI,KAAK;AACxC,QAAI,WAAW;AACb,gBAAU,IAAI,QAAQ;AAAA,IAAA,OACjB;AACA,yBAAA,SAAQ,IAAI,OAAO,oBAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;AAAA,IAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBF,IAAuB,OAAW,UAAkC;AAClE,QAAI,SAAS,UAAU;AAChB,4BAAA,oCAAA,WAAa,OAAO;AAAA,eAChB,OAAO;AAChB,4BAAK,iCAAL,WAAe;AAAA,IAAK,OACf;AACL,4BAAK,+BAAL;AAAA,IAAa;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BF,KAAwB,UAAa,UAA6C;AAChF,UAAM,YAAY,mBAAK,SAAQ,IAAI,KAAK;AAExC,QAAI,CAAC,UAAW;AAGhB,eAAW,YAAY,CAAC,GAAG,SAAS,GAAG;AACrC,UAAI,SAAS,GAAG,QAAQ,MAAM,OAAO;AACnC;AAAA,MAAA;AAAA,IACF;AAAA,EACF;AAEJ;AArFE;AADK;AAgDL,YAAU,WAAA;AACR,qBAAK,SAAQ,MAAM;AAAA;AAGrB,uBAA6B,OAAU;AAChC,qBAAA,SAAQ,OAAO,KAAK;AAAA;AAG3B,iBAAA,SAAgC,OAAU,UAAiC;AACzE,QAAM,YAAY,mBAAK,SAAQ,IAAI,KAAK;AAExC,MAAI,WAAW;AACb,cAAU,OAAO,QAAQ;AAAA,EAAA;AAC3B;"}
1
+ {"version":3,"file":"emitter.mjs","sources":["../src/emitter.ts"],"sourcesContent":["import type { AnyFunction, AnyObject } from './types';\n\n/**\n * 事件类型映射,key 为事件名称,value 为事件参数类型数组\n */\nexport type EmitterMap = Record<string, unknown[]>;\n\n/**\n * 事件监听器函数类型\n * @template E - EmitterMap 类型\n * @template K - 事件名称类型\n */\nexport type EmitterListener<E extends EmitterMap, K extends keyof E> = (...payloads: E[K]) => false | unknown;\n\n/**\n * 事件发射器类,用于管理事件监听和触发\n * @template E - 事件类型映射\n *\n * @example\n * type MyEvents = {\n * 'click': [x: number, y: number];\n * 'change': [value: string];\n * };\n *\n * const emitter = new Emitter<MyEvents>();\n * emitter.on('click', (x, y) => {\n * console.log(`Clicked at (${x}, ${y})`);\n * });\n * emitter.emit('click', 10, 20);\n */\nexport class Emitter<E extends EmitterMap> {\n #events: Map<keyof E, Set<AnyFunction>> = new Map();\n\n /**\n * 注册事件监听器\n * @param event - 要监听的事件名称\n * @param listener - 事件监听器函数\n * @example\n * emitter.on('click', (x, y) => {\n * console.log(`Clicked at (${x}, ${y})`);\n * });\n */\n on<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {\n const listeners = this.#events.get(event);\n if (listeners) {\n listeners.add(listener);\n } else {\n this.#events.set(event, new Set([listener]));\n }\n }\n\n /**\n * 移除事件监听器,有三种使用方式:\n * 1. 移除特定事件的特定监听器\n * 2. 移除特定事件的所有监听器\n * 3. 移除所有事件的所有监听器\n * @param event - 要移除的事件名称(可选)\n * @param listener - 要移除的监听器函数(可选)\n * @example\n * // 移除特定事件的特定监听器\n * emitter.off('click', clickHandler);\n *\n * // 移除特定事件的所有监听器\n * emitter.off('click');\n *\n * // 移除所有事件的所有监听器\n * emitter.off();\n */\n off<K extends keyof E>(event?: K, listener?: EmitterListener<E, K>) {\n if (event && listener) {\n this.#offListener(event, listener);\n } else if (event) {\n this.#offEvent(event);\n } else {\n this.#offAll();\n }\n }\n\n #offAll() {\n this.#events.clear();\n }\n\n #offEvent<K extends keyof E>(event: K) {\n this.#events.delete(event);\n }\n\n #offListener<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {\n const listeners = this.#events.get(event);\n\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * 触发指定事件,调用所有注册的监听器\n * @param event - 要触发的事件名称\n * @param payloads - 传递给监听器的参数\n * @remarks\n * 监听器会按照注册的顺序依次执行,如果某个监听器返回 false,\n * 则后续监听器将不会被执行\n * @example\n * emitter.emit('click', 10, 20);\n */\n emit<K extends keyof E>(event: K, ...payloads: Parameters<EmitterListener<E, K>>) {\n const listeners = this.#events.get(event) as Set<EmitterListener<E, K>> | undefined;\n\n if (!listeners) return;\n\n // 避免在 emit、on 的过程中改变 listeners 从而影响本次 emit\n for (const listener of [...listeners]) {\n if (listener(...payloads) === false) {\n break;\n }\n }\n }\n}\n"],"names":[],"mappings":"AA8BO,MAAM,QAA8B;AAAA,EACzC,8BAA8C,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWlD,GAAsB,OAAU,UAAiC;AAC/D,UAAM,YAAY,KAAK,QAAQ,IAAI,KAAK;AACxC,QAAI,WAAW;AACb,gBAAU,IAAI,QAAQ;AAAA,IAAA,OACjB;AACA,WAAA,QAAQ,IAAI,OAAO,oBAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;AAAA,IAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBF,IAAuB,OAAW,UAAkC;AAClE,QAAI,SAAS,UAAU;AAChB,WAAA,aAAa,OAAO,QAAQ;AAAA,eACxB,OAAO;AAChB,WAAK,UAAU,KAAK;AAAA,IAAA,OACf;AACL,WAAK,QAAQ;AAAA,IAAA;AAAA,EACf;AAAA,EAGF,UAAU;AACR,SAAK,QAAQ,MAAM;AAAA,EAAA;AAAA,EAGrB,UAA6B,OAAU;AAChC,SAAA,QAAQ,OAAO,KAAK;AAAA,EAAA;AAAA,EAG3B,aAAgC,OAAU,UAAiC;AACzE,UAAM,YAAY,KAAK,QAAQ,IAAI,KAAK;AAExC,QAAI,WAAW;AACb,gBAAU,OAAO,QAAQ;AAAA,IAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF,KAAwB,UAAa,UAA6C;AAChF,UAAM,YAAY,KAAK,QAAQ,IAAI,KAAK;AAExC,QAAI,CAAC,UAAW;AAGhB,eAAW,YAAY,CAAC,GAAG,SAAS,GAAG;AACrC,UAAI,SAAS,GAAG,QAAQ,MAAM,OAAO;AACnC;AAAA,MAAA;AAAA,IACF;AAAA,EACF;AAEJ;"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const VERSION = "1.7.0";
3
+ const VERSION = "1.9.0";
4
4
  exports.VERSION = VERSION;
5
5
  //# sourceMappingURL=index.cjs.map
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- const VERSION = "1.7.0";
1
+ const VERSION = "1.9.0";
2
2
  export {
3
3
  VERSION
4
4
  };
package/dist/timer.cjs CHANGED
@@ -86,7 +86,7 @@ function timeInterval(callback, interval, options) {
86
86
  return {
87
87
  start() {
88
88
  if (!canStart()) return;
89
- if (options == null ? void 0 : options.leading) {
89
+ if (options?.leading) {
90
90
  start();
91
91
  } else {
92
92
  timeId = setTimeout(start, interval);
@@ -94,19 +94,19 @@ function timeInterval(callback, interval, options) {
94
94
  },
95
95
  stop() {
96
96
  if (!canStop()) return;
97
- if (options == null ? void 0 : options.trailing) execute();
97
+ if (options?.trailing) execute();
98
98
  clearTimeout(timeId);
99
99
  stop();
100
100
  },
101
101
  pause() {
102
102
  if (!canPause()) return;
103
- if (options == null ? void 0 : options.trailing) execute();
103
+ if (options?.trailing) execute();
104
104
  clearTimeout(timeId);
105
105
  pause();
106
106
  },
107
107
  resume(immediate) {
108
108
  if (!canResume()) return;
109
- if (immediate || (options == null ? void 0 : options.leading)) {
109
+ if (immediate || options?.leading) {
110
110
  resume();
111
111
  } else {
112
112
  timeId = setTimeout(resume, interval);
@@ -1 +1 @@
1
- {"version":3,"file":"timer.cjs","sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态接口\n */\nexport type TimerState = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\nexport type TimerHandler = {\n /**\n * 开始\n */\n start: () => void;\n /**\n * 暂停\n */\n pause: () => void;\n /**\n * 恢复\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止\n */\n stop: () => void;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * 创建间隔定时器核心函数\n *\n * @param nextTime - 用于安排下一次执行的函数\n * @param effect - 每次执行的回调函数,接收定时器状态和可选的next函数\n * @returns 返回包含控制方法的对象\n */\nexport function makeInterval(\n nextTime: (call: () => void) => void,\n effect: (timer: TimerState, next?: () => void) => unknown,\n) {\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState = {\n times: ++times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n };\n\n if (effect.length === 2) {\n effect(state, () => {\n nextTime(execute);\n });\n } else {\n effect(state);\n nextTime(execute);\n }\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n execute();\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\nexport type TimerOptions = {\n /**\n * 是否在定时器开始时立即执行回调\n */\n leading?: boolean;\n /**\n * 是否在定时器停止时执行最后一次回调\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个基于 `setTimeout` 的间隔定时器\n *\n * @param callback - 每次间隔执行的回调函数,接收定时器状态和可选的 `next` 函数\n * @param interval - 间隔时间,单位为毫秒\n * @param options - 配置选项\n * @returns {TimerHandler}\n */\nexport function timeInterval(\n callback: (state: TimerState, next?: () => void) => unknown,\n interval: number,\n options?: TimerOptions,\n): TimerHandler {\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval((call) => {\n timeId = setTimeout(call, interval);\n }, callback);\n\n return {\n start() {\n if (!canStart()) return;\n\n if (options?.leading) {\n start();\n } else {\n timeId = setTimeout(start, interval);\n }\n },\n\n stop() {\n if (!canStop()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n stop();\n },\n\n pause() {\n if (!canPause()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n pause();\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n\n if (immediate || options?.leading) {\n resume();\n } else {\n timeId = setTimeout(resume, interval);\n }\n },\n };\n}\n"],"names":[],"mappings":";;AA6DA,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,cAAc;AASJ,SAAA,aACd,UACA,QACA;AACA,MAAI,UAAU;AACd,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,UAAU;AACd,MAAI,WAAW;AACf,MAAI,QAAQ;AACZ,MAAI,SAAS;AACb,MAAI,cAAc;AAElB,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,aAAc;AAEtB,UAAA,MAAM,KAAK,IAAI;AACrB,UAAM,eAAe,SAAS,IAAI,MAAM,SAAS;AAClC,mBAAA;AACN,aAAA;AACT,UAAM,QAAoB;AAAA,MACxB,OAAO,EAAE;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,aAAa,UAAU,IAAI,MAAM,UAAU;AAAA,MAC3C;AAAA,MACA;AAAA,IACF;AAEI,QAAA,OAAO,WAAW,GAAG;AACvB,aAAO,OAAO,MAAM;AAClB,iBAAS,OAAO;AAAA,MAAA,CACjB;AAAA,IAAA,OACI;AACL,aAAO,KAAK;AACZ,eAAS,OAAO;AAAA,IAAA;AAAA,EAEpB;AAEM,QAAA,WAAW,MAAM,WAAW;AAClC,QAAM,QAAQ,MAAM;AACd,QAAA,CAAC,WAAY;AACR,aAAA;AACT,cAAU,KAAK,IAAI;AACX,YAAA;AAAA,EACV;AAEM,QAAA,UAAU,MAAM,WAAW;AACjC,QAAM,OAAO,MAAM;AACb,QAAA,CAAC,UAAW;AACP,aAAA;AACT,aAAS,KAAK,IAAI;AAAA,EACpB;AAEM,QAAA,WAAW,MAAM,WAAW;AAClC,QAAM,QAAQ,MAAM;AACd,QAAA,CAAC,WAAY;AACR,aAAA;AACT,cAAU,KAAK,IAAI;AAAA,EACrB;AAEM,QAAA,YAAY,MAAM,WAAW;AACnC,QAAM,SAAS,MAAM;AACf,QAAA,CAAC,YAAa;AACT,aAAA;AACT,eAAW,KAAK,IAAI;AACX,aAAA;AACD,YAAA;AAAA,EACV;AAEO,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAqBgB,SAAA,aACd,UACA,UACA,SACc;AACV,MAAA;AACJ,QAAM,EAAE,UAAU,SAAS,UAAU,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAY,IAAA,aAAa,CAAC,SAAS;AACpG,aAAA,WAAW,MAAM,QAAQ;AAAA,KACjC,QAAQ;AAEJ,SAAA;AAAA,IACL,QAAQ;AACF,UAAA,CAAC,WAAY;AAEjB,UAAI,mCAAS,SAAS;AACd,cAAA;AAAA,MAAA,OACD;AACI,iBAAA,WAAW,OAAO,QAAQ;AAAA,MAAA;AAAA,IAEvC;AAAA,IAEA,OAAO;AACD,UAAA,CAAC,UAAW;AACZ,UAAA,mCAAS,SAAkB,SAAA;AAE/B,mBAAa,MAAM;AACd,WAAA;AAAA,IACP;AAAA,IAEA,QAAQ;AACF,UAAA,CAAC,WAAY;AACb,UAAA,mCAAS,SAAkB,SAAA;AAE/B,mBAAa,MAAM;AACb,YAAA;AAAA,IACR;AAAA,IAEA,OAAO,WAAqB;AACtB,UAAA,CAAC,YAAa;AAEd,UAAA,cAAa,mCAAS,UAAS;AAC1B,eAAA;AAAA,MAAA,OACF;AACI,iBAAA,WAAW,QAAQ,QAAQ;AAAA,MAAA;AAAA,IACtC;AAAA,EAEJ;AACF;;;"}
1
+ {"version":3,"file":"timer.cjs","sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态接口\n */\nexport type TimerState = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\nexport type TimerHandler = {\n /**\n * 开始\n */\n start: () => void;\n /**\n * 暂停\n */\n pause: () => void;\n /**\n * 恢复\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止\n */\n stop: () => void;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * 创建间隔定时器核心函数\n *\n * @param nextTime - 用于安排下一次执行的函数\n * @param effect - 每次执行的回调函数,接收定时器状态和可选的next函数\n * @returns 返回包含控制方法的对象\n */\nexport function makeInterval(\n nextTime: (call: () => void) => void,\n effect: (timer: TimerState, next?: () => void) => unknown,\n) {\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState = {\n times: ++times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n };\n\n if (effect.length === 2) {\n effect(state, () => {\n nextTime(execute);\n });\n } else {\n effect(state);\n nextTime(execute);\n }\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n execute();\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\nexport type TimerOptions = {\n /**\n * 是否在定时器开始时立即执行回调\n */\n leading?: boolean;\n /**\n * 是否在定时器停止时执行最后一次回调\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个基于 `setTimeout` 的间隔定时器\n *\n * @param callback - 每次间隔执行的回调函数,接收定时器状态和可选的 `next` 函数\n * @param interval - 间隔时间,单位为毫秒\n * @param options - 配置选项\n * @returns {TimerHandler}\n */\nexport function timeInterval(\n callback: (state: TimerState, next?: () => void) => unknown,\n interval: number,\n options?: TimerOptions,\n): TimerHandler {\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval((call) => {\n timeId = setTimeout(call, interval);\n }, callback);\n\n return {\n start() {\n if (!canStart()) return;\n\n if (options?.leading) {\n start();\n } else {\n timeId = setTimeout(start, interval);\n }\n },\n\n stop() {\n if (!canStop()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n stop();\n },\n\n pause() {\n if (!canPause()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n pause();\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n\n if (immediate || options?.leading) {\n resume();\n } else {\n timeId = setTimeout(resume, interval);\n }\n },\n };\n}\n"],"names":[],"mappings":";;AA6DA,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,cAAc;AASJ,SAAA,aACd,UACA,QACA;AACA,MAAI,UAAU;AACd,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,UAAU;AACd,MAAI,WAAW;AACf,MAAI,QAAQ;AACZ,MAAI,SAAS;AACb,MAAI,cAAc;AAElB,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,aAAc;AAEtB,UAAA,MAAM,KAAK,IAAI;AACrB,UAAM,eAAe,SAAS,IAAI,MAAM,SAAS;AAClC,mBAAA;AACN,aAAA;AACT,UAAM,QAAoB;AAAA,MACxB,OAAO,EAAE;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,aAAa,UAAU,IAAI,MAAM,UAAU;AAAA,MAC3C;AAAA,MACA;AAAA,IACF;AAEI,QAAA,OAAO,WAAW,GAAG;AACvB,aAAO,OAAO,MAAM;AAClB,iBAAS,OAAO;AAAA,MAAA,CACjB;AAAA,IAAA,OACI;AACL,aAAO,KAAK;AACZ,eAAS,OAAO;AAAA,IAAA;AAAA,EAEpB;AAEM,QAAA,WAAW,MAAM,WAAW;AAClC,QAAM,QAAQ,MAAM;AACd,QAAA,CAAC,WAAY;AACR,aAAA;AACT,cAAU,KAAK,IAAI;AACX,YAAA;AAAA,EACV;AAEM,QAAA,UAAU,MAAM,WAAW;AACjC,QAAM,OAAO,MAAM;AACb,QAAA,CAAC,UAAW;AACP,aAAA;AACT,aAAS,KAAK,IAAI;AAAA,EACpB;AAEM,QAAA,WAAW,MAAM,WAAW;AAClC,QAAM,QAAQ,MAAM;AACd,QAAA,CAAC,WAAY;AACR,aAAA;AACT,cAAU,KAAK,IAAI;AAAA,EACrB;AAEM,QAAA,YAAY,MAAM,WAAW;AACnC,QAAM,SAAS,MAAM;AACf,QAAA,CAAC,YAAa;AACT,aAAA;AACT,eAAW,KAAK,IAAI;AACX,aAAA;AACD,YAAA;AAAA,EACV;AAEO,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAqBgB,SAAA,aACd,UACA,UACA,SACc;AACV,MAAA;AACJ,QAAM,EAAE,UAAU,SAAS,UAAU,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAY,IAAA,aAAa,CAAC,SAAS;AACpG,aAAA,WAAW,MAAM,QAAQ;AAAA,KACjC,QAAQ;AAEJ,SAAA;AAAA,IACL,QAAQ;AACF,UAAA,CAAC,WAAY;AAEjB,UAAI,SAAS,SAAS;AACd,cAAA;AAAA,MAAA,OACD;AACI,iBAAA,WAAW,OAAO,QAAQ;AAAA,MAAA;AAAA,IAEvC;AAAA,IAEA,OAAO;AACD,UAAA,CAAC,UAAW;AACZ,UAAA,SAAS,SAAkB,SAAA;AAE/B,mBAAa,MAAM;AACd,WAAA;AAAA,IACP;AAAA,IAEA,QAAQ;AACF,UAAA,CAAC,WAAY;AACb,UAAA,SAAS,SAAkB,SAAA;AAE/B,mBAAa,MAAM;AACb,YAAA;AAAA,IACR;AAAA,IAEA,OAAO,WAAqB;AACtB,UAAA,CAAC,YAAa;AAEd,UAAA,aAAa,SAAS,SAAS;AAC1B,eAAA;AAAA,MAAA,OACF;AACI,iBAAA,WAAW,QAAQ,QAAQ;AAAA,MAAA;AAAA,IACtC;AAAA,EAEJ;AACF;;;"}
package/dist/timer.mjs CHANGED
@@ -84,7 +84,7 @@ function timeInterval(callback, interval, options) {
84
84
  return {
85
85
  start() {
86
86
  if (!canStart()) return;
87
- if (options == null ? void 0 : options.leading) {
87
+ if (options?.leading) {
88
88
  start();
89
89
  } else {
90
90
  timeId = setTimeout(start, interval);
@@ -92,19 +92,19 @@ function timeInterval(callback, interval, options) {
92
92
  },
93
93
  stop() {
94
94
  if (!canStop()) return;
95
- if (options == null ? void 0 : options.trailing) execute();
95
+ if (options?.trailing) execute();
96
96
  clearTimeout(timeId);
97
97
  stop();
98
98
  },
99
99
  pause() {
100
100
  if (!canPause()) return;
101
- if (options == null ? void 0 : options.trailing) execute();
101
+ if (options?.trailing) execute();
102
102
  clearTimeout(timeId);
103
103
  pause();
104
104
  },
105
105
  resume(immediate) {
106
106
  if (!canResume()) return;
107
- if (immediate || (options == null ? void 0 : options.leading)) {
107
+ if (immediate || options?.leading) {
108
108
  resume();
109
109
  } else {
110
110
  timeId = setTimeout(resume, interval);
@@ -1 +1 @@
1
- {"version":3,"file":"timer.mjs","sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态接口\n */\nexport type TimerState = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\nexport type TimerHandler = {\n /**\n * 开始\n */\n start: () => void;\n /**\n * 暂停\n */\n pause: () => void;\n /**\n * 恢复\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止\n */\n stop: () => void;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * 创建间隔定时器核心函数\n *\n * @param nextTime - 用于安排下一次执行的函数\n * @param effect - 每次执行的回调函数,接收定时器状态和可选的next函数\n * @returns 返回包含控制方法的对象\n */\nexport function makeInterval(\n nextTime: (call: () => void) => void,\n effect: (timer: TimerState, next?: () => void) => unknown,\n) {\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState = {\n times: ++times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n };\n\n if (effect.length === 2) {\n effect(state, () => {\n nextTime(execute);\n });\n } else {\n effect(state);\n nextTime(execute);\n }\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n execute();\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\nexport type TimerOptions = {\n /**\n * 是否在定时器开始时立即执行回调\n */\n leading?: boolean;\n /**\n * 是否在定时器停止时执行最后一次回调\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个基于 `setTimeout` 的间隔定时器\n *\n * @param callback - 每次间隔执行的回调函数,接收定时器状态和可选的 `next` 函数\n * @param interval - 间隔时间,单位为毫秒\n * @param options - 配置选项\n * @returns {TimerHandler}\n */\nexport function timeInterval(\n callback: (state: TimerState, next?: () => void) => unknown,\n interval: number,\n options?: TimerOptions,\n): TimerHandler {\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval((call) => {\n timeId = setTimeout(call, interval);\n }, callback);\n\n return {\n start() {\n if (!canStart()) return;\n\n if (options?.leading) {\n start();\n } else {\n timeId = setTimeout(start, interval);\n }\n },\n\n stop() {\n if (!canStop()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n stop();\n },\n\n pause() {\n if (!canPause()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n pause();\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n\n if (immediate || options?.leading) {\n resume();\n } else {\n timeId = setTimeout(resume, interval);\n }\n },\n };\n}\n"],"names":[],"mappings":"AA6DA,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,cAAc;AASJ,SAAA,aACd,UACA,QACA;AACA,MAAI,UAAU;AACd,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,UAAU;AACd,MAAI,WAAW;AACf,MAAI,QAAQ;AACZ,MAAI,SAAS;AACb,MAAI,cAAc;AAElB,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,aAAc;AAEtB,UAAA,MAAM,KAAK,IAAI;AACrB,UAAM,eAAe,SAAS,IAAI,MAAM,SAAS;AAClC,mBAAA;AACN,aAAA;AACT,UAAM,QAAoB;AAAA,MACxB,OAAO,EAAE;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,aAAa,UAAU,IAAI,MAAM,UAAU;AAAA,MAC3C;AAAA,MACA;AAAA,IACF;AAEI,QAAA,OAAO,WAAW,GAAG;AACvB,aAAO,OAAO,MAAM;AAClB,iBAAS,OAAO;AAAA,MAAA,CACjB;AAAA,IAAA,OACI;AACL,aAAO,KAAK;AACZ,eAAS,OAAO;AAAA,IAAA;AAAA,EAEpB;AAEM,QAAA,WAAW,MAAM,WAAW;AAClC,QAAM,QAAQ,MAAM;AACd,QAAA,CAAC,WAAY;AACR,aAAA;AACT,cAAU,KAAK,IAAI;AACX,YAAA;AAAA,EACV;AAEM,QAAA,UAAU,MAAM,WAAW;AACjC,QAAM,OAAO,MAAM;AACb,QAAA,CAAC,UAAW;AACP,aAAA;AACT,aAAS,KAAK,IAAI;AAAA,EACpB;AAEM,QAAA,WAAW,MAAM,WAAW;AAClC,QAAM,QAAQ,MAAM;AACd,QAAA,CAAC,WAAY;AACR,aAAA;AACT,cAAU,KAAK,IAAI;AAAA,EACrB;AAEM,QAAA,YAAY,MAAM,WAAW;AACnC,QAAM,SAAS,MAAM;AACf,QAAA,CAAC,YAAa;AACT,aAAA;AACT,eAAW,KAAK,IAAI;AACX,aAAA;AACD,YAAA;AAAA,EACV;AAEO,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAqBgB,SAAA,aACd,UACA,UACA,SACc;AACV,MAAA;AACJ,QAAM,EAAE,UAAU,SAAS,UAAU,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAY,IAAA,aAAa,CAAC,SAAS;AACpG,aAAA,WAAW,MAAM,QAAQ;AAAA,KACjC,QAAQ;AAEJ,SAAA;AAAA,IACL,QAAQ;AACF,UAAA,CAAC,WAAY;AAEjB,UAAI,mCAAS,SAAS;AACd,cAAA;AAAA,MAAA,OACD;AACI,iBAAA,WAAW,OAAO,QAAQ;AAAA,MAAA;AAAA,IAEvC;AAAA,IAEA,OAAO;AACD,UAAA,CAAC,UAAW;AACZ,UAAA,mCAAS,SAAkB,SAAA;AAE/B,mBAAa,MAAM;AACd,WAAA;AAAA,IACP;AAAA,IAEA,QAAQ;AACF,UAAA,CAAC,WAAY;AACb,UAAA,mCAAS,SAAkB,SAAA;AAE/B,mBAAa,MAAM;AACb,YAAA;AAAA,IACR;AAAA,IAEA,OAAO,WAAqB;AACtB,UAAA,CAAC,YAAa;AAEd,UAAA,cAAa,mCAAS,UAAS;AAC1B,eAAA;AAAA,MAAA,OACF;AACI,iBAAA,WAAW,QAAQ,QAAQ;AAAA,MAAA;AAAA,IACtC;AAAA,EAEJ;AACF;"}
1
+ {"version":3,"file":"timer.mjs","sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态接口\n */\nexport type TimerState = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\nexport type TimerHandler = {\n /**\n * 开始\n */\n start: () => void;\n /**\n * 暂停\n */\n pause: () => void;\n /**\n * 恢复\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止\n */\n stop: () => void;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * 创建间隔定时器核心函数\n *\n * @param nextTime - 用于安排下一次执行的函数\n * @param effect - 每次执行的回调函数,接收定时器状态和可选的next函数\n * @returns 返回包含控制方法的对象\n */\nexport function makeInterval(\n nextTime: (call: () => void) => void,\n effect: (timer: TimerState, next?: () => void) => unknown,\n) {\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState = {\n times: ++times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n };\n\n if (effect.length === 2) {\n effect(state, () => {\n nextTime(execute);\n });\n } else {\n effect(state);\n nextTime(execute);\n }\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n execute();\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\nexport type TimerOptions = {\n /**\n * 是否在定时器开始时立即执行回调\n */\n leading?: boolean;\n /**\n * 是否在定时器停止时执行最后一次回调\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个基于 `setTimeout` 的间隔定时器\n *\n * @param callback - 每次间隔执行的回调函数,接收定时器状态和可选的 `next` 函数\n * @param interval - 间隔时间,单位为毫秒\n * @param options - 配置选项\n * @returns {TimerHandler}\n */\nexport function timeInterval(\n callback: (state: TimerState, next?: () => void) => unknown,\n interval: number,\n options?: TimerOptions,\n): TimerHandler {\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval((call) => {\n timeId = setTimeout(call, interval);\n }, callback);\n\n return {\n start() {\n if (!canStart()) return;\n\n if (options?.leading) {\n start();\n } else {\n timeId = setTimeout(start, interval);\n }\n },\n\n stop() {\n if (!canStop()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n stop();\n },\n\n pause() {\n if (!canPause()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n pause();\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n\n if (immediate || options?.leading) {\n resume();\n } else {\n timeId = setTimeout(resume, interval);\n }\n },\n };\n}\n"],"names":[],"mappings":"AA6DA,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,cAAc;AASJ,SAAA,aACd,UACA,QACA;AACA,MAAI,UAAU;AACd,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,UAAU;AACd,MAAI,WAAW;AACf,MAAI,QAAQ;AACZ,MAAI,SAAS;AACb,MAAI,cAAc;AAElB,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,aAAc;AAEtB,UAAA,MAAM,KAAK,IAAI;AACrB,UAAM,eAAe,SAAS,IAAI,MAAM,SAAS;AAClC,mBAAA;AACN,aAAA;AACT,UAAM,QAAoB;AAAA,MACxB,OAAO,EAAE;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,aAAa,UAAU,IAAI,MAAM,UAAU;AAAA,MAC3C;AAAA,MACA;AAAA,IACF;AAEI,QAAA,OAAO,WAAW,GAAG;AACvB,aAAO,OAAO,MAAM;AAClB,iBAAS,OAAO;AAAA,MAAA,CACjB;AAAA,IAAA,OACI;AACL,aAAO,KAAK;AACZ,eAAS,OAAO;AAAA,IAAA;AAAA,EAEpB;AAEM,QAAA,WAAW,MAAM,WAAW;AAClC,QAAM,QAAQ,MAAM;AACd,QAAA,CAAC,WAAY;AACR,aAAA;AACT,cAAU,KAAK,IAAI;AACX,YAAA;AAAA,EACV;AAEM,QAAA,UAAU,MAAM,WAAW;AACjC,QAAM,OAAO,MAAM;AACb,QAAA,CAAC,UAAW;AACP,aAAA;AACT,aAAS,KAAK,IAAI;AAAA,EACpB;AAEM,QAAA,WAAW,MAAM,WAAW;AAClC,QAAM,QAAQ,MAAM;AACd,QAAA,CAAC,WAAY;AACR,aAAA;AACT,cAAU,KAAK,IAAI;AAAA,EACrB;AAEM,QAAA,YAAY,MAAM,WAAW;AACnC,QAAM,SAAS,MAAM;AACf,QAAA,CAAC,YAAa;AACT,aAAA;AACT,eAAW,KAAK,IAAI;AACX,aAAA;AACD,YAAA;AAAA,EACV;AAEO,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAqBgB,SAAA,aACd,UACA,UACA,SACc;AACV,MAAA;AACJ,QAAM,EAAE,UAAU,SAAS,UAAU,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAY,IAAA,aAAa,CAAC,SAAS;AACpG,aAAA,WAAW,MAAM,QAAQ;AAAA,KACjC,QAAQ;AAEJ,SAAA;AAAA,IACL,QAAQ;AACF,UAAA,CAAC,WAAY;AAEjB,UAAI,SAAS,SAAS;AACd,cAAA;AAAA,MAAA,OACD;AACI,iBAAA,WAAW,OAAO,QAAQ;AAAA,MAAA;AAAA,IAEvC;AAAA,IAEA,OAAO;AACD,UAAA,CAAC,UAAW;AACZ,UAAA,SAAS,SAAkB,SAAA;AAE/B,mBAAa,MAAM;AACd,WAAA;AAAA,IACP;AAAA,IAEA,QAAQ;AACF,UAAA,CAAC,WAAY;AACb,UAAA,SAAS,SAAkB,SAAA;AAE/B,mBAAa,MAAM;AACb,YAAA;AAAA,IACR;AAAA,IAEA,OAAO,WAAqB;AACtB,UAAA,CAAC,YAAa;AAEd,UAAA,aAAa,SAAS,SAAS;AAC1B,eAAA;AAAA,MAAA,OACF;AACI,iBAAA,WAAW,QAAQ,QAAQ;AAAA,MAAA;AAAA,IACtC;AAAA,EAEJ;AACF;"}
package/dist/types.d.ts CHANGED
@@ -17,6 +17,27 @@ export type KeysOf<T> = {
17
17
  * 任意数组
18
18
  */
19
19
  export type AnyArray = Array<unknown>;
20
+ /**
21
+ * 原始值类型
22
+ * @description 包含 JavaScript 中的所有原始类型,包括 string、number、boolean、bigint、symbol、null、undefined,以及 void 和 never
23
+ * @example
24
+ * ```typescript
25
+ * type Primitive = PrimitiveValue;
26
+ * // string | number | boolean | bigint | symbol | null | undefined | void | never
27
+ * ```
28
+ */
29
+ export type PrimitiveValue = string | number | boolean | bigint | symbol | null | undefined | void | never;
30
+ /**
31
+ * 引用类型值
32
+ * @description 表示所有非原始类型的值,即除了 PrimitiveValue 之外的所有类型
33
+ * @example
34
+ * ```typescript
35
+ * const obj: ReferenceValue = { a: 1 };
36
+ * const arr: ReferenceValue = [1, 2, 3];
37
+ * const func: ReferenceValue = () => {};
38
+ * ```
39
+ */
40
+ export type ReferenceValue = object;
20
41
  /**
21
42
  * 任意函数
22
43
  */
@@ -35,10 +56,25 @@ export type MaybePromise<T> = T | Promise<T>;
35
56
  export type MaybeCallable<T> = T | (() => T);
36
57
  /**
37
58
  * 深度部分类型
59
+ * @example
60
+ * ```typescript
61
+ * type PartialObj = DeepPartial<{ a: 1, b: { c: 2 } }>;
62
+ * // { a?: 1 | undefined, b?: { c?: 2 | undefined } | undefined }
63
+ * ```
38
64
  */
39
65
  export type DeepPartial<T> = T extends object ? {
40
66
  [P in keyof T]?: DeepPartial<T[P]>;
41
67
  } : T;
68
+ /**
69
+ * 将联合类型转换为交叉类型
70
+ * @ref https://juejin.cn/post/6994102811218673700#heading-24
71
+ * @template T - 联合类型
72
+ * @example
73
+ * ```typescript
74
+ * type Result = UnionToIntersection<{ a: 1 } | { b: 2 }>;
75
+ * // { a: 1 } & { b: 2 }
76
+ * ```
77
+ */
42
78
  export type UnionToIntersection<T> = (T extends any ? (arg: T) => void : never) extends (arg: infer U) => void ? U : never;
43
79
  /**
44
80
  * 从联合类型中提取最后一个类型
@@ -49,8 +85,22 @@ type _UnionLast<U> = UnionToIntersection<U extends U ? (x: U) => 0 : never> exte
49
85
  * 将联合类型转换为元组类型
50
86
  * @template U - 联合类型
51
87
  * @template Last - 联合类型中的最后一个类型
88
+ * @example
89
+ * ```ts
90
+ * type T3 = UnionToTuple<'a' | 'b' | 'c' | 'd'>;
91
+ * // ['a', 'b', 'c', 'd']
92
+ * ```
52
93
  */
53
94
  export type UnionToTuple<U, Last = _UnionLast<U>> = [U] extends [never] ? [] : [...UnionToTuple<Exclude<U, Last>>, Last];
95
+ /**
96
+ * 将交叉类型合并为一个对象类型
97
+ * @template A - 交叉类型
98
+ * @example
99
+ * ```typescript
100
+ * type Merged = MergeIntersection<{ a: string } & { b: number }>;
101
+ * // { a: string; b: number }
102
+ * ```
103
+ */
54
104
  export type MergeIntersection<A> = A extends infer T ? {
55
105
  [Key in keyof T]: T[Key];
56
106
  } : never;
@@ -62,4 +112,31 @@ export type LowercaseStartString = `${'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' |
62
112
  * 以大写字母开头的字符串类型
63
113
  */
64
114
  export type UppercaseStartString = `${'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'}${string}`;
115
+ /**
116
+ * 判断是否是空对象
117
+ * @example
118
+ * ```typescript
119
+ * type Result = IsEmptyObject<{}>; // true
120
+ * type Result2 = IsEmptyObject<{ a: 1 }>; // false
121
+ * ```
122
+ */
123
+ export type IsEmptyObject<T> = keyof T extends never ? true : false;
124
+ /**
125
+ * 判断对象是否只有一个属性
126
+ * @example
127
+ * ```typescript
128
+ * type Result = IsOnlyProperty<{ a: 1 }, 'a'>; // true
129
+ * type Result2 = IsOnlyProperty<{ a: 1, b: 2 }, 'a'>; // false
130
+ * ```
131
+ */
132
+ export type IsOnlyProperty<T, P> = keyof T extends P ? true : false;
133
+ /**
134
+ * 判断对象是否具有指定属性
135
+ * @example
136
+ * ```typescript
137
+ * type Result = HasProperty<{ a: 1, b: 2 }, 'a'>; // true
138
+ * type Result2 = HasProperty<{ a: 1, b: 2 }, 'c'>; // false
139
+ * ```
140
+ */
141
+ export type HasProperty<T, K> = K extends keyof T ? true : false;
65
142
  export {};
package/dist/url.cjs CHANGED
@@ -6,18 +6,18 @@ function urlParse(url) {
6
6
  result = new globalThis.URL(url);
7
7
  } catch (e) {
8
8
  }
9
- const protocol = (result == null ? void 0 : result.protocol) || "";
10
- const host = (result == null ? void 0 : result.host) || "";
9
+ const protocol = result?.protocol || "";
10
+ const host = result?.host || "";
11
11
  return {
12
12
  protocol,
13
13
  host,
14
- hostname: (result == null ? void 0 : result.hostname) || "",
15
- port: (result == null ? void 0 : result.port) || "",
16
- pathname: (result == null ? void 0 : result.pathname) || "",
17
- search: (result == null ? void 0 : result.search) || "",
18
- hash: (result == null ? void 0 : result.hash) || "",
19
- username: (result == null ? void 0 : result.username) || "",
20
- password: (result == null ? void 0 : result.password) || ""
14
+ hostname: result?.hostname || "",
15
+ port: result?.port || "",
16
+ pathname: result?.pathname || "",
17
+ search: result?.search || "",
18
+ hash: result?.hash || "",
19
+ username: result?.username || "",
20
+ password: result?.password || ""
21
21
  };
22
22
  }
23
23
  function urlStringify(url) {
package/dist/url.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"url.cjs","sources":["../src/url.ts"],"sourcesContent":["/**\n * URL 元信息\n */\nexport type UrlMeta = {\n /**\n * 协议部分,包含冒号,例如 \"https:\"。\n */\n protocol: string;\n /**\n * 主机部分,包括主机名和端口。\n */\n host: string;\n /**\n * 主机名部分。\n */\n hostname: string;\n /**\n * 端口部分。\n */\n port: string;\n /**\n * 路径部分。\n */\n pathname: string;\n /**\n * 查询字符串部分。\n */\n search: string;\n /**\n * 哈希部分。\n */\n hash: string;\n /**\n * 用户名部分。\n */\n username: string;\n /**\n * 密码部分。\n */\n password: string;\n};\n\n/**\n * 解析 URL 字符串为组件对象。\n * @param url - 需要解析的 URL 字符串。\n * @returns 包含解析后 URL 组件的对象。\n */\nexport function urlParse(url: string): UrlMeta {\n let result: URL | null = null;\n\n try {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n result = new globalThis.URL(url);\n } catch (e) {\n // ignore\n }\n\n const protocol = result?.protocol || '';\n const host = result?.host || '';\n\n return {\n protocol,\n host,\n hostname: result?.hostname || '',\n port: result?.port || '',\n pathname: result?.pathname || '',\n search: result?.search || '',\n hash: result?.hash || '',\n username: result?.username || '',\n password: result?.password || '',\n };\n}\n\n/**\n * 将 UrlMeta 对象转换回 URL 字符串。\n * @param url - 需要转换的 UrlMeta 对象。\n * @returns 转换后的 URL 字符串。\n */\nexport function urlStringify(url: UrlMeta) {\n const { protocol, hostname, port, pathname, search, hash, username, password } = url;\n return [\n protocol ? `${protocol}//` : '',\n username && password ? `${username}:${password}@` : '',\n hostname,\n port ? `:${port}` : '',\n pathname,\n search,\n hash,\n ]\n .filter(Boolean)\n .join('');\n}\n"],"names":[],"mappings":";;AA+CO,SAAS,SAAS,KAAsB;AAC7C,MAAI,SAAqB;AAErB,MAAA;AAGO,aAAA,IAAI,WAAW,IAAI,GAAG;AAAA,WACxB,GAAG;AAAA,EAAA;AAIN,QAAA,YAAW,iCAAQ,aAAY;AAC/B,QAAA,QAAO,iCAAQ,SAAQ;AAEtB,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA,WAAU,iCAAQ,aAAY;AAAA,IAC9B,OAAM,iCAAQ,SAAQ;AAAA,IACtB,WAAU,iCAAQ,aAAY;AAAA,IAC9B,SAAQ,iCAAQ,WAAU;AAAA,IAC1B,OAAM,iCAAQ,SAAQ;AAAA,IACtB,WAAU,iCAAQ,aAAY;AAAA,IAC9B,WAAU,iCAAQ,aAAY;AAAA,EAChC;AACF;AAOO,SAAS,aAAa,KAAc;AACnC,QAAA,EAAE,UAAU,UAAU,MAAM,UAAU,QAAQ,MAAM,UAAU,SAAA,IAAa;AAC1E,SAAA;AAAA,IACL,WAAW,GAAG,QAAQ,OAAO;AAAA,IAC7B,YAAY,WAAW,GAAG,QAAQ,IAAI,QAAQ,MAAM;AAAA,IACpD;AAAA,IACA,OAAO,IAAI,IAAI,KAAK;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EAEC,EAAA,OAAO,OAAO,EACd,KAAK,EAAE;AACZ;;;"}
1
+ {"version":3,"file":"url.cjs","sources":["../src/url.ts"],"sourcesContent":["/**\n * URL 元信息\n */\nexport type UrlMeta = {\n /**\n * 协议部分,包含冒号,例如 \"https:\"。\n */\n protocol: string;\n /**\n * 主机部分,包括主机名和端口。\n */\n host: string;\n /**\n * 主机名部分。\n */\n hostname: string;\n /**\n * 端口部分。\n */\n port: string;\n /**\n * 路径部分。\n */\n pathname: string;\n /**\n * 查询字符串部分。\n */\n search: string;\n /**\n * 哈希部分。\n */\n hash: string;\n /**\n * 用户名部分。\n */\n username: string;\n /**\n * 密码部分。\n */\n password: string;\n};\n\n/**\n * 解析 URL 字符串为组件对象。\n * @param url - 需要解析的 URL 字符串。\n * @returns 包含解析后 URL 组件的对象。\n */\nexport function urlParse(url: string): UrlMeta {\n let result: URL | null = null;\n\n try {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n result = new globalThis.URL(url);\n } catch (e) {\n // ignore\n }\n\n const protocol = result?.protocol || '';\n const host = result?.host || '';\n\n return {\n protocol,\n host,\n hostname: result?.hostname || '',\n port: result?.port || '',\n pathname: result?.pathname || '',\n search: result?.search || '',\n hash: result?.hash || '',\n username: result?.username || '',\n password: result?.password || '',\n };\n}\n\n/**\n * 将 UrlMeta 对象转换回 URL 字符串。\n * @param url - 需要转换的 UrlMeta 对象。\n * @returns 转换后的 URL 字符串。\n */\nexport function urlStringify(url: UrlMeta) {\n const { protocol, hostname, port, pathname, search, hash, username, password } = url;\n return [\n protocol ? `${protocol}//` : '',\n username && password ? `${username}:${password}@` : '',\n hostname,\n port ? `:${port}` : '',\n pathname,\n search,\n hash,\n ]\n .filter(Boolean)\n .join('');\n}\n"],"names":[],"mappings":";;AA+CO,SAAS,SAAS,KAAsB;AAC7C,MAAI,SAAqB;AAErB,MAAA;AAGO,aAAA,IAAI,WAAW,IAAI,GAAG;AAAA,WACxB,GAAG;AAAA,EAAA;AAIN,QAAA,WAAW,QAAQ,YAAY;AAC/B,QAAA,OAAO,QAAQ,QAAQ;AAEtB,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,QAAQ,YAAY;AAAA,IAC9B,MAAM,QAAQ,QAAQ;AAAA,IACtB,UAAU,QAAQ,YAAY;AAAA,IAC9B,QAAQ,QAAQ,UAAU;AAAA,IAC1B,MAAM,QAAQ,QAAQ;AAAA,IACtB,UAAU,QAAQ,YAAY;AAAA,IAC9B,UAAU,QAAQ,YAAY;AAAA,EAChC;AACF;AAOO,SAAS,aAAa,KAAc;AACnC,QAAA,EAAE,UAAU,UAAU,MAAM,UAAU,QAAQ,MAAM,UAAU,SAAA,IAAa;AAC1E,SAAA;AAAA,IACL,WAAW,GAAG,QAAQ,OAAO;AAAA,IAC7B,YAAY,WAAW,GAAG,QAAQ,IAAI,QAAQ,MAAM;AAAA,IACpD;AAAA,IACA,OAAO,IAAI,IAAI,KAAK;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EAEC,EAAA,OAAO,OAAO,EACd,KAAK,EAAE;AACZ;;;"}
package/dist/url.mjs CHANGED
@@ -4,18 +4,18 @@ function urlParse(url) {
4
4
  result = new globalThis.URL(url);
5
5
  } catch (e) {
6
6
  }
7
- const protocol = (result == null ? void 0 : result.protocol) || "";
8
- const host = (result == null ? void 0 : result.host) || "";
7
+ const protocol = result?.protocol || "";
8
+ const host = result?.host || "";
9
9
  return {
10
10
  protocol,
11
11
  host,
12
- hostname: (result == null ? void 0 : result.hostname) || "",
13
- port: (result == null ? void 0 : result.port) || "",
14
- pathname: (result == null ? void 0 : result.pathname) || "",
15
- search: (result == null ? void 0 : result.search) || "",
16
- hash: (result == null ? void 0 : result.hash) || "",
17
- username: (result == null ? void 0 : result.username) || "",
18
- password: (result == null ? void 0 : result.password) || ""
12
+ hostname: result?.hostname || "",
13
+ port: result?.port || "",
14
+ pathname: result?.pathname || "",
15
+ search: result?.search || "",
16
+ hash: result?.hash || "",
17
+ username: result?.username || "",
18
+ password: result?.password || ""
19
19
  };
20
20
  }
21
21
  function urlStringify(url) {
package/dist/url.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"url.mjs","sources":["../src/url.ts"],"sourcesContent":["/**\n * URL 元信息\n */\nexport type UrlMeta = {\n /**\n * 协议部分,包含冒号,例如 \"https:\"。\n */\n protocol: string;\n /**\n * 主机部分,包括主机名和端口。\n */\n host: string;\n /**\n * 主机名部分。\n */\n hostname: string;\n /**\n * 端口部分。\n */\n port: string;\n /**\n * 路径部分。\n */\n pathname: string;\n /**\n * 查询字符串部分。\n */\n search: string;\n /**\n * 哈希部分。\n */\n hash: string;\n /**\n * 用户名部分。\n */\n username: string;\n /**\n * 密码部分。\n */\n password: string;\n};\n\n/**\n * 解析 URL 字符串为组件对象。\n * @param url - 需要解析的 URL 字符串。\n * @returns 包含解析后 URL 组件的对象。\n */\nexport function urlParse(url: string): UrlMeta {\n let result: URL | null = null;\n\n try {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n result = new globalThis.URL(url);\n } catch (e) {\n // ignore\n }\n\n const protocol = result?.protocol || '';\n const host = result?.host || '';\n\n return {\n protocol,\n host,\n hostname: result?.hostname || '',\n port: result?.port || '',\n pathname: result?.pathname || '',\n search: result?.search || '',\n hash: result?.hash || '',\n username: result?.username || '',\n password: result?.password || '',\n };\n}\n\n/**\n * 将 UrlMeta 对象转换回 URL 字符串。\n * @param url - 需要转换的 UrlMeta 对象。\n * @returns 转换后的 URL 字符串。\n */\nexport function urlStringify(url: UrlMeta) {\n const { protocol, hostname, port, pathname, search, hash, username, password } = url;\n return [\n protocol ? `${protocol}//` : '',\n username && password ? `${username}:${password}@` : '',\n hostname,\n port ? `:${port}` : '',\n pathname,\n search,\n hash,\n ]\n .filter(Boolean)\n .join('');\n}\n"],"names":[],"mappings":"AA+CO,SAAS,SAAS,KAAsB;AAC7C,MAAI,SAAqB;AAErB,MAAA;AAGO,aAAA,IAAI,WAAW,IAAI,GAAG;AAAA,WACxB,GAAG;AAAA,EAAA;AAIN,QAAA,YAAW,iCAAQ,aAAY;AAC/B,QAAA,QAAO,iCAAQ,SAAQ;AAEtB,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA,WAAU,iCAAQ,aAAY;AAAA,IAC9B,OAAM,iCAAQ,SAAQ;AAAA,IACtB,WAAU,iCAAQ,aAAY;AAAA,IAC9B,SAAQ,iCAAQ,WAAU;AAAA,IAC1B,OAAM,iCAAQ,SAAQ;AAAA,IACtB,WAAU,iCAAQ,aAAY;AAAA,IAC9B,WAAU,iCAAQ,aAAY;AAAA,EAChC;AACF;AAOO,SAAS,aAAa,KAAc;AACnC,QAAA,EAAE,UAAU,UAAU,MAAM,UAAU,QAAQ,MAAM,UAAU,SAAA,IAAa;AAC1E,SAAA;AAAA,IACL,WAAW,GAAG,QAAQ,OAAO;AAAA,IAC7B,YAAY,WAAW,GAAG,QAAQ,IAAI,QAAQ,MAAM;AAAA,IACpD;AAAA,IACA,OAAO,IAAI,IAAI,KAAK;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EAEC,EAAA,OAAO,OAAO,EACd,KAAK,EAAE;AACZ;"}
1
+ {"version":3,"file":"url.mjs","sources":["../src/url.ts"],"sourcesContent":["/**\n * URL 元信息\n */\nexport type UrlMeta = {\n /**\n * 协议部分,包含冒号,例如 \"https:\"。\n */\n protocol: string;\n /**\n * 主机部分,包括主机名和端口。\n */\n host: string;\n /**\n * 主机名部分。\n */\n hostname: string;\n /**\n * 端口部分。\n */\n port: string;\n /**\n * 路径部分。\n */\n pathname: string;\n /**\n * 查询字符串部分。\n */\n search: string;\n /**\n * 哈希部分。\n */\n hash: string;\n /**\n * 用户名部分。\n */\n username: string;\n /**\n * 密码部分。\n */\n password: string;\n};\n\n/**\n * 解析 URL 字符串为组件对象。\n * @param url - 需要解析的 URL 字符串。\n * @returns 包含解析后 URL 组件的对象。\n */\nexport function urlParse(url: string): UrlMeta {\n let result: URL | null = null;\n\n try {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n result = new globalThis.URL(url);\n } catch (e) {\n // ignore\n }\n\n const protocol = result?.protocol || '';\n const host = result?.host || '';\n\n return {\n protocol,\n host,\n hostname: result?.hostname || '',\n port: result?.port || '',\n pathname: result?.pathname || '',\n search: result?.search || '',\n hash: result?.hash || '',\n username: result?.username || '',\n password: result?.password || '',\n };\n}\n\n/**\n * 将 UrlMeta 对象转换回 URL 字符串。\n * @param url - 需要转换的 UrlMeta 对象。\n * @returns 转换后的 URL 字符串。\n */\nexport function urlStringify(url: UrlMeta) {\n const { protocol, hostname, port, pathname, search, hash, username, password } = url;\n return [\n protocol ? `${protocol}//` : '',\n username && password ? `${username}:${password}@` : '',\n hostname,\n port ? `:${port}` : '',\n pathname,\n search,\n hash,\n ]\n .filter(Boolean)\n .join('');\n}\n"],"names":[],"mappings":"AA+CO,SAAS,SAAS,KAAsB;AAC7C,MAAI,SAAqB;AAErB,MAAA;AAGO,aAAA,IAAI,WAAW,IAAI,GAAG;AAAA,WACxB,GAAG;AAAA,EAAA;AAIN,QAAA,WAAW,QAAQ,YAAY;AAC/B,QAAA,OAAO,QAAQ,QAAQ;AAEtB,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,QAAQ,YAAY;AAAA,IAC9B,MAAM,QAAQ,QAAQ;AAAA,IACtB,UAAU,QAAQ,YAAY;AAAA,IAC9B,QAAQ,QAAQ,UAAU;AAAA,IAC1B,MAAM,QAAQ,QAAQ;AAAA,IACtB,UAAU,QAAQ,YAAY;AAAA,IAC9B,UAAU,QAAQ,YAAY;AAAA,EAChC;AACF;AAOO,SAAS,aAAa,KAAc;AACnC,QAAA,EAAE,UAAU,UAAU,MAAM,UAAU,QAAQ,MAAM,UAAU,SAAA,IAAa;AAC1E,SAAA;AAAA,IACL,WAAW,GAAG,QAAQ,OAAO;AAAA,IAC7B,YAAY,WAAW,GAAG,QAAQ,IAAI,QAAQ,MAAM;AAAA,IACpD;AAAA,IACA,OAAO,IAAI,IAAI,KAAK;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EAEC,EAAA,OAAO,OAAO,EACd,KAAK,EAAE;AACZ;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudcome/utils-core",
3
- "version": "1.8.0",
3
+ "version": "1.9.1",
4
4
  "description": "cloudcome core utils",
5
5
  "engines": {
6
6
  "node": ">=22"