a2bei4-utils 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +2 -0
- package/dist/a2bei4.utils.cjs.js +1112 -0
- package/dist/a2bei4.utils.cjs.js.map +1 -0
- package/dist/a2bei4.utils.cjs.min.js +2 -0
- package/dist/a2bei4.utils.cjs.min.js.map +1 -0
- package/dist/a2bei4.utils.esm.js +1070 -0
- package/dist/a2bei4.utils.esm.js.map +1 -0
- package/dist/a2bei4.utils.esm.min.js +2 -0
- package/dist/a2bei4.utils.esm.min.js.map +1 -0
- package/dist/a2bei4.utils.umd.js +1118 -0
- package/dist/a2bei4.utils.umd.js.map +1 -0
- package/dist/a2bei4.utils.umd.min.js +2 -0
- package/dist/a2bei4.utils.umd.min.js.map +1 -0
- package/dist/arr.cjs +34 -0
- package/dist/arr.cjs.map +1 -0
- package/dist/arr.js +31 -0
- package/dist/arr.js.map +1 -0
- package/dist/browser.cjs +60 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.js +56 -0
- package/dist/browser.js.map +1 -0
- package/dist/common.cjs +391 -0
- package/dist/common.cjs.map +1 -0
- package/dist/common.js +373 -0
- package/dist/common.js.map +1 -0
- package/dist/date.cjs +195 -0
- package/dist/date.cjs.map +1 -0
- package/dist/date.js +188 -0
- package/dist/date.js.map +1 -0
- package/dist/download.cjs +70 -0
- package/dist/download.cjs.map +1 -0
- package/dist/download.js +64 -0
- package/dist/download.js.map +1 -0
- package/dist/evt.cjs +155 -0
- package/dist/evt.cjs.map +1 -0
- package/dist/evt.js +152 -0
- package/dist/evt.js.map +1 -0
- package/dist/id.cjs +75 -0
- package/dist/id.cjs.map +1 -0
- package/dist/id.js +72 -0
- package/dist/id.js.map +1 -0
- package/dist/timer.cjs +57 -0
- package/dist/timer.cjs.map +1 -0
- package/dist/timer.js +55 -0
- package/dist/timer.js.map +1 -0
- package/dist/tree.cjs +99 -0
- package/dist/tree.cjs.map +1 -0
- package/dist/tree.js +95 -0
- package/dist/tree.js.map +1 -0
- package/package.json +146 -0
- package/readme.txt +18 -0
- package/types/arr.d.ts +18 -0
- package/types/browser.d.ts +51 -0
- package/types/common.d.ts +170 -0
- package/types/date.d.ts +77 -0
- package/types/download.d.ts +39 -0
- package/types/evt.d.ts +52 -0
- package/types/id.d.ts +39 -0
- package/types/index.d.ts +499 -0
- package/types/timer.d.ts +32 -0
- package/types/tree.d.ts +30 -0
package/dist/evt.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 简单、高性能的通用事件总线。
|
|
3
|
+
* - 支持命名空间事件
|
|
4
|
+
* - 支持一次性监听器
|
|
5
|
+
* - 返回唯一 flag,用于精确卸载
|
|
6
|
+
* - emit 时可选自定义 this 指向
|
|
7
|
+
*/
|
|
8
|
+
class MyEvent {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.evtPool = new Map();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 注册事件监听器。
|
|
15
|
+
* @param {string} name - 事件名
|
|
16
|
+
* @param {Function} fn - 回调函数
|
|
17
|
+
* @returns {string} flag - 唯一标识,用于 off
|
|
18
|
+
*/
|
|
19
|
+
on(name, fn) {
|
|
20
|
+
let flag = Date.now() + "_" + parseInt(Math.random() * 1e8);
|
|
21
|
+
const evtItem = {
|
|
22
|
+
flag,
|
|
23
|
+
fn
|
|
24
|
+
};
|
|
25
|
+
if (this.evtPool.has(name)) {
|
|
26
|
+
this.evtPool.get(name).push(evtItem);
|
|
27
|
+
} else {
|
|
28
|
+
this.evtPool.set(name, [evtItem]);
|
|
29
|
+
}
|
|
30
|
+
return flag;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 注册一次性监听器,触发后自动移除。
|
|
35
|
+
* @param {string} name - 事件名
|
|
36
|
+
* @param {Function} fn - 回调函数
|
|
37
|
+
* @returns {string} flag - 唯一标识
|
|
38
|
+
*/
|
|
39
|
+
once(name, fn) {
|
|
40
|
+
const _this = this;
|
|
41
|
+
let wrapper;
|
|
42
|
+
wrapper = function (data) {
|
|
43
|
+
_this.off(name, wrapper);
|
|
44
|
+
fn.call(this, data);
|
|
45
|
+
};
|
|
46
|
+
return this.on(name, wrapper);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 移除指定事件监听器。
|
|
51
|
+
* @param {string} name - 事件名
|
|
52
|
+
* @param {Function|string} fnOrFlag - 回调函数或 flag
|
|
53
|
+
*/
|
|
54
|
+
off(name, fnOrFlag) {
|
|
55
|
+
if (!this.evtPool.has(name)) return;
|
|
56
|
+
const evtItems = this.evtPool.get(name);
|
|
57
|
+
const filtered = evtItems.filter((item) => item.fn !== fnOrFlag && item.flag !== fnOrFlag);
|
|
58
|
+
if (filtered.length === 0) {
|
|
59
|
+
this.evtPool.delete(name);
|
|
60
|
+
} else {
|
|
61
|
+
this.evtPool.set(name, filtered);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 触发事件(同步执行)。
|
|
67
|
+
* @param {string} name - 事件名
|
|
68
|
+
* @param {*} [data] - 任意载荷
|
|
69
|
+
* @param {*} [fnThis] - 回调内部 this 指向,默认 undefined
|
|
70
|
+
*/
|
|
71
|
+
emit(name, data, fnThis) {
|
|
72
|
+
if (!this.evtPool.has(name)) return;
|
|
73
|
+
const evtItems = this.evtPool.get(name);
|
|
74
|
+
evtItems.forEach((item) => {
|
|
75
|
+
try {
|
|
76
|
+
item.fn.call(fnThis, data);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.error(`Error in event listener for "${name}":`, err);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 跨页通信插件:通过 localStorage + storage 事件将当前实例的 emit 广播到其他同源页面。
|
|
86
|
+
* 支持节流、命名空间隔离。
|
|
87
|
+
*/
|
|
88
|
+
const MyEvent_CrossPagePlugin = (() => {
|
|
89
|
+
const INSTALLED = new WeakSet(); // 防止重复安装
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
/**
|
|
93
|
+
* 为指定 MyEvent 实例安装跨页插件。
|
|
94
|
+
* @param {MyEvent} bus - 事件总线实例
|
|
95
|
+
* @param {Options} [opts] - 配置项
|
|
96
|
+
*/
|
|
97
|
+
install(bus, opts = {}) {
|
|
98
|
+
if (INSTALLED.has(bus)) return;
|
|
99
|
+
INSTALLED.add(bus);
|
|
100
|
+
|
|
101
|
+
const ns = `___my-event-cross-page-${opts.namespace || "default"}___`;
|
|
102
|
+
const delay = opts.throttle || 16;
|
|
103
|
+
let last = 0;
|
|
104
|
+
|
|
105
|
+
// 1、重写 emit
|
|
106
|
+
const rawEmit = bus.emit;
|
|
107
|
+
bus.emit = function (name, data, fnThis) {
|
|
108
|
+
rawEmit.call(bus, name, data, fnThis); // 本地先执行
|
|
109
|
+
const now = Date.now();
|
|
110
|
+
if (now - last < delay) return;
|
|
111
|
+
last = now;
|
|
112
|
+
const key = ns + name;
|
|
113
|
+
try {
|
|
114
|
+
localStorage.setItem(key, JSON.stringify({ name, data, ts: now }));
|
|
115
|
+
localStorage.removeItem(key); // 触发 storage 事件
|
|
116
|
+
} catch (e) {}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// 2、监听其他页广播
|
|
120
|
+
function onStorageHandler(e) {
|
|
121
|
+
if (!e.key || !e.key.startsWith(ns)) return;
|
|
122
|
+
let payload;
|
|
123
|
+
try {
|
|
124
|
+
payload = JSON.parse(e.newValue || "{}");
|
|
125
|
+
} catch {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (!payload.ts || payload.ts <= last) return;
|
|
129
|
+
rawEmit.call(bus, e.key.slice(ns.length), payload.data); // 仅本地
|
|
130
|
+
}
|
|
131
|
+
addEventListener("storage", onStorageHandler);
|
|
132
|
+
|
|
133
|
+
// 3、保存卸载器
|
|
134
|
+
bus._uninstallCrossPage = () => {
|
|
135
|
+
removeEventListener("storage", onStorageHandler);
|
|
136
|
+
bus.emit = rawEmit;
|
|
137
|
+
INSTALLED.delete(bus);
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 卸载插件,恢复原始 emit 并停止监听。
|
|
143
|
+
* @param {MyEvent} bus - 事件总线实例
|
|
144
|
+
*/
|
|
145
|
+
uninstall(bus) {
|
|
146
|
+
if (typeof bus._uninstallCrossPage === "function") bus._uninstallCrossPage();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
})();
|
|
150
|
+
|
|
151
|
+
export { MyEvent, MyEvent_CrossPagePlugin };
|
|
152
|
+
//# sourceMappingURL=evt.js.map
|
package/dist/evt.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evt.js","sources":["../src/source/evt.js"],"sourcesContent":["/**\r\n * 简单、高性能的通用事件总线。\r\n * - 支持命名空间事件\r\n * - 支持一次性监听器\r\n * - 返回唯一 flag,用于精确卸载\r\n * - emit 时可选自定义 this 指向\r\n */\r\nexport class MyEvent {\r\n constructor() {\r\n this.evtPool = new Map();\r\n }\r\n\r\n /**\r\n * 注册事件监听器。\r\n * @param {string} name - 事件名\r\n * @param {Function} fn - 回调函数\r\n * @returns {string} flag - 唯一标识,用于 off\r\n */\r\n on(name, fn) {\r\n let flag = Date.now() + \"_\" + parseInt(Math.random() * 1e8);\r\n const evtItem = {\r\n flag,\r\n fn\r\n };\r\n if (this.evtPool.has(name)) {\r\n this.evtPool.get(name).push(evtItem);\r\n } else {\r\n this.evtPool.set(name, [evtItem]);\r\n }\r\n return flag;\r\n }\r\n\r\n /**\r\n * 注册一次性监听器,触发后自动移除。\r\n * @param {string} name - 事件名\r\n * @param {Function} fn - 回调函数\r\n * @returns {string} flag - 唯一标识\r\n */\r\n once(name, fn) {\r\n const _this = this;\r\n let wrapper;\r\n wrapper = function (data) {\r\n _this.off(name, wrapper);\r\n fn.call(this, data);\r\n };\r\n return this.on(name, wrapper);\r\n }\r\n\r\n /**\r\n * 移除指定事件监听器。\r\n * @param {string} name - 事件名\r\n * @param {Function|string} fnOrFlag - 回调函数或 flag\r\n */\r\n off(name, fnOrFlag) {\r\n if (!this.evtPool.has(name)) return;\r\n const evtItems = this.evtPool.get(name);\r\n const filtered = evtItems.filter((item) => item.fn !== fnOrFlag && item.flag !== fnOrFlag);\r\n if (filtered.length === 0) {\r\n this.evtPool.delete(name);\r\n } else {\r\n this.evtPool.set(name, filtered);\r\n }\r\n }\r\n\r\n /**\r\n * 触发事件(同步执行)。\r\n * @param {string} name - 事件名\r\n * @param {*} [data] - 任意载荷\r\n * @param {*} [fnThis] - 回调内部 this 指向,默认 undefined\r\n */\r\n emit(name, data, fnThis) {\r\n if (!this.evtPool.has(name)) return;\r\n const evtItems = this.evtPool.get(name);\r\n evtItems.forEach((item) => {\r\n try {\r\n item.fn.call(fnThis, data);\r\n } catch (err) {\r\n console.error(`Error in event listener for \"${name}\":`, err);\r\n }\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * 跨页通信插件:通过 localStorage + storage 事件将当前实例的 emit 广播到其他同源页面。\r\n * 支持节流、命名空间隔离。\r\n */\r\nexport const MyEvent_CrossPagePlugin = (() => {\r\n const INSTALLED = new WeakSet(); // 防止重复安装\r\n\r\n return {\r\n /**\r\n * 为指定 MyEvent 实例安装跨页插件。\r\n * @param {MyEvent} bus - 事件总线实例\r\n * @param {Options} [opts] - 配置项\r\n */\r\n install(bus, opts = {}) {\r\n if (INSTALLED.has(bus)) return;\r\n INSTALLED.add(bus);\r\n\r\n const ns = `___my-event-cross-page-${opts.namespace || \"default\"}___`;\r\n const delay = opts.throttle || 16;\r\n let last = 0;\r\n\r\n // 1、重写 emit\r\n const rawEmit = bus.emit;\r\n bus.emit = function (name, data, fnThis) {\r\n rawEmit.call(bus, name, data, fnThis); // 本地先执行\r\n const now = Date.now();\r\n if (now - last < delay) return;\r\n last = now;\r\n const key = ns + name;\r\n try {\r\n localStorage.setItem(key, JSON.stringify({ name, data, ts: now }));\r\n localStorage.removeItem(key); // 触发 storage 事件\r\n } catch (e) {}\r\n };\r\n\r\n // 2、监听其他页广播\r\n function onStorageHandler(e) {\r\n if (!e.key || !e.key.startsWith(ns)) return;\r\n let payload;\r\n try {\r\n payload = JSON.parse(e.newValue || \"{}\");\r\n } catch {\r\n return;\r\n }\r\n if (!payload.ts || payload.ts <= last) return;\r\n rawEmit.call(bus, e.key.slice(ns.length), payload.data); // 仅本地\r\n }\r\n addEventListener(\"storage\", onStorageHandler);\r\n\r\n // 3、保存卸载器\r\n bus._uninstallCrossPage = () => {\r\n removeEventListener(\"storage\", onStorageHandler);\r\n bus.emit = rawEmit;\r\n INSTALLED.delete(bus);\r\n };\r\n },\r\n\r\n /**\r\n * 卸载插件,恢复原始 emit 并停止监听。\r\n * @param {MyEvent} bus - 事件总线实例\r\n */\r\n uninstall(bus) {\r\n if (typeof bus._uninstallCrossPage === \"function\") bus._uninstallCrossPage();\r\n }\r\n };\r\n})();\r\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,OAAO,CAAC;AACrB,IAAI,WAAW,GAAG;AAClB,QAAQ,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;AACjC,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE;AACjB,QAAQ,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;AACpE,QAAQ,MAAM,OAAO,GAAG;AACxB,YAAY,IAAI;AAChB,YAAY,EAAE;AACd,SAAS,CAAC;AACV,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACpC,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACjD,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9C,QAAQ,CAAC;AACT,QAAQ,OAAO,IAAI,CAAC;AACpB,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE;AACnB,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC;AAC3B,QAAQ,IAAI,OAAO,CAAC;AACpB,QAAQ,OAAO,GAAG,UAAU,IAAI,EAAE;AAClC,YAAY,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACrC,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAChC,QAAQ,CAAC,CAAC;AACV,QAAQ,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACtC,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE;AACxB,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO;AAC5C,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChD,QAAQ,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;AACnG,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;AACnC,YAAY,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACtC,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;AAC7B,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO;AAC5C,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChD,QAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK;AACnC,YAAY,IAAI;AAChB,gBAAgB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC3C,YAAY,CAAC,CAAC,OAAO,GAAG,EAAE;AAC1B,gBAAgB,OAAO,CAAC,KAAK,CAAC,CAAC,6BAA6B,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;AAC7E,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,CAAC;AACX,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA;AACA;AACA;AACY,MAAC,uBAAuB,GAAG,CAAC,MAAM;AAC9C,IAAI,MAAM,SAAS,GAAG,IAAI,OAAO,EAAE,CAAC;AACpC;AACA,IAAI,OAAO;AACX;AACA;AACA;AACA;AACA;AACA,QAAQ,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE;AAChC,YAAY,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO;AAC3C,YAAY,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC/B;AACA,YAAY,MAAM,EAAE,GAAG,CAAC,uBAAuB,EAAE,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;AAClF,YAAY,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;AAC9C,YAAY,IAAI,IAAI,GAAG,CAAC,CAAC;AACzB;AACA;AACA,YAAY,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC;AACrC,YAAY,GAAG,CAAC,IAAI,GAAG,UAAU,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;AACrD,gBAAgB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACtD,gBAAgB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACvC,gBAAgB,IAAI,GAAG,GAAG,IAAI,GAAG,KAAK,EAAE,OAAO;AAC/C,gBAAgB,IAAI,GAAG,GAAG,CAAC;AAC3B,gBAAgB,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;AACtC,gBAAgB,IAAI;AACpB,oBAAoB,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;AACvF,oBAAoB,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACjD,gBAAgB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC9B,YAAY,CAAC,CAAC;AACd;AACA;AACA,YAAY,SAAS,gBAAgB,CAAC,CAAC,EAAE;AACzC,gBAAgB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,OAAO;AAC5D,gBAAgB,IAAI,OAAO,CAAC;AAC5B,gBAAgB,IAAI;AACpB,oBAAoB,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;AAC7D,gBAAgB,CAAC,CAAC,MAAM;AACxB,oBAAoB,OAAO;AAC3B,gBAAgB,CAAC;AACjB,gBAAgB,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,OAAO,CAAC,EAAE,IAAI,IAAI,EAAE,OAAO;AAC9D,gBAAgB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;AACxE,YAAY,CAAC;AACb,YAAY,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAC1D;AACA;AACA,YAAY,GAAG,CAAC,mBAAmB,GAAG,MAAM;AAC5C,gBAAgB,mBAAmB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AACjE,gBAAgB,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC;AACnC,gBAAgB,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACtC,YAAY,CAAC,CAAC;AACd,QAAQ,CAAC;AACT;AACA;AACA;AACA;AACA;AACA,QAAQ,SAAS,CAAC,GAAG,EAAE;AACvB,YAAY,IAAI,OAAO,GAAG,CAAC,mBAAmB,KAAK,UAAU,EAAE,GAAG,CAAC,mBAAmB,EAAE,CAAC;AACzF,QAAQ,CAAC;AACT,KAAK,CAAC;AACN,CAAC;;;;"}
|
package/dist/id.cjs
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 生成 RFC4122 版本 4 的 GUID/UUID。
|
|
5
|
+
* 收集来源:《基于mvc的javascript web富应用开发》 书中介绍是Robert Kieffer写的,还留了网址 http://goo.gl/0b0hu ,但实际访问不了。
|
|
6
|
+
* 格式:`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`
|
|
7
|
+
*
|
|
8
|
+
* @returns {string} 36 位大写 GUID
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // A2E0F340-6C3B-4D7F-B8C1-1E4F6A8B9C0D
|
|
12
|
+
* console.log(getGUID())
|
|
13
|
+
*/
|
|
14
|
+
function getGUID() {
|
|
15
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
16
|
+
let r = (Math.random() * 16) | 0,
|
|
17
|
+
v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
18
|
+
return v.toString(16).toUpperCase();
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 分布式短 ID 生成器。
|
|
24
|
+
* 格式:`${timestamp}${flag}${serial}`,其中:
|
|
25
|
+
* - timestamp:毫秒级时间戳
|
|
26
|
+
* - flag:客户端标识串(自定义)
|
|
27
|
+
* - serial:同一毫秒内的序号,左补零到固定长度
|
|
28
|
+
*/
|
|
29
|
+
class MyId {
|
|
30
|
+
#ts = Date.now(); // 时间戳
|
|
31
|
+
#sn = 0; // 序号(保证同一客户端之间的唯一项)
|
|
32
|
+
#flag = ""; // 客户端标识(保证不同客户端之间的唯一项)
|
|
33
|
+
#len = 5; // 序号位长度(我的电脑测试,同一时间戳内可以for循环执行了1000次左右,没有一次超过3k,所以5位应该够用了)
|
|
34
|
+
// 测试代码
|
|
35
|
+
// let obj = {[Date.now()]:[]}; try { for (let i = 0; i < 100000; i++) { obj[Date.now()].push(i); } } catch { console.log(obj[Object.getOwnPropertyNames(obj)[0]].length); }
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {object} [option]
|
|
39
|
+
* @param {string} [option.flag] - 客户端标识,默认空串
|
|
40
|
+
* @param {number} [option.len=5] - 序号位长度(位数),安全范围 ≥0
|
|
41
|
+
*/
|
|
42
|
+
constructor(option = {}) {
|
|
43
|
+
if (option) {
|
|
44
|
+
if (typeof option.flag === "string") {
|
|
45
|
+
this.#flag = option.flag;
|
|
46
|
+
}
|
|
47
|
+
if (Number.isSafeInteger(option.len) && len >= 0) {
|
|
48
|
+
this.#len = option.len;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 生成下一个全局唯一字符串 ID。
|
|
55
|
+
* 同一毫秒序号自动递增;序号溢出时会在控制台警告。
|
|
56
|
+
* @returns {string}
|
|
57
|
+
*/
|
|
58
|
+
nextId() {
|
|
59
|
+
let ts = Date.now();
|
|
60
|
+
if (ts === this.#ts) {
|
|
61
|
+
this.#sn++;
|
|
62
|
+
if (this.#sn >= 10 ** this.#len) {
|
|
63
|
+
console.log("长度不够用了!!!");
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
this.#sn = 0;
|
|
67
|
+
this.#ts = ts;
|
|
68
|
+
}
|
|
69
|
+
return ts.toString() + this.#flag + this.#sn.toString().padStart(this.#len, "0");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
exports.MyId = MyId;
|
|
74
|
+
exports.getGUID = getGUID;
|
|
75
|
+
//# sourceMappingURL=id.cjs.map
|
package/dist/id.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.cjs","sources":["../src/source/id.js"],"sourcesContent":["/**\r\n * 生成 RFC4122 版本 4 的 GUID/UUID。\r\n * 收集来源:《基于mvc的javascript web富应用开发》 书中介绍是Robert Kieffer写的,还留了网址 http://goo.gl/0b0hu ,但实际访问不了。\r\n * 格式:`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`\r\n *\r\n * @returns {string} 36 位大写 GUID\r\n *\r\n * @example\r\n * // A2E0F340-6C3B-4D7F-B8C1-1E4F6A8B9C0D\r\n * console.log(getGUID())\r\n */\r\nexport function getGUID() {\r\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\r\n let r = (Math.random() * 16) | 0,\r\n v = c == \"x\" ? r : (r & 0x3) | 0x8;\r\n return v.toString(16).toUpperCase();\r\n });\r\n}\r\n\r\n/**\r\n * 分布式短 ID 生成器。\r\n * 格式:`${timestamp}${flag}${serial}`,其中:\r\n * - timestamp:毫秒级时间戳\r\n * - flag:客户端标识串(自定义)\r\n * - serial:同一毫秒内的序号,左补零到固定长度\r\n */\r\nexport class MyId {\r\n #ts = Date.now(); //\t时间戳\r\n #sn = 0; //\t序号(保证同一客户端之间的唯一项)\r\n #flag = \"\"; //\t客户端标识(保证不同客户端之间的唯一项)\r\n #len = 5; //\t序号位长度(我的电脑测试,同一时间戳内可以for循环执行了1000次左右,没有一次超过3k,所以5位应该够用了)\r\n // 测试代码\r\n // let obj = {[Date.now()]:[]}; try { for (let i = 0; i < 100000; i++) { obj[Date.now()].push(i); } } catch { console.log(obj[Object.getOwnPropertyNames(obj)[0]].length); }\r\n\r\n /**\r\n * @param {object} [option]\r\n * @param {string} [option.flag] - 客户端标识,默认空串\r\n * @param {number} [option.len=5] - 序号位长度(位数),安全范围 ≥0\r\n */\r\n constructor(option = {}) {\r\n if (option) {\r\n if (typeof option.flag === \"string\") {\r\n this.#flag = option.flag;\r\n }\r\n if (Number.isSafeInteger(option.len) && len >= 0) {\r\n this.#len = option.len;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 生成下一个全局唯一字符串 ID。\r\n * 同一毫秒序号自动递增;序号溢出时会在控制台警告。\r\n * @returns {string}\r\n */\r\n nextId() {\r\n let ts = Date.now();\r\n if (ts === this.#ts) {\r\n this.#sn++;\r\n if (this.#sn >= 10 ** this.#len) {\r\n console.log(\"长度不够用了!!!\");\r\n }\r\n } else {\r\n this.#sn = 0;\r\n this.#ts = ts;\r\n }\r\n return ts.toString() + this.#flag + this.#sn.toString().padStart(this.#len, \"0\");\r\n }\r\n}\r\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,OAAO,GAAG;AAC1B,IAAI,OAAO,sCAAsC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK;AAC1E,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;AACxC,YAAY,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC;AAC/C,QAAQ,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAC5C,IAAI,CAAC,CAAC,CAAC;AACP,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,IAAI,CAAC;AAClB,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACrB,IAAI,GAAG,GAAG,CAAC,CAAC;AACZ,IAAI,KAAK,GAAG,EAAE,CAAC;AACf,IAAI,IAAI,GAAG,CAAC,CAAC;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,GAAG,EAAE,EAAE;AAC7B,QAAQ,IAAI,MAAM,EAAE;AACpB,YAAY,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE;AACjD,gBAAgB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC;AACzC,YAAY,CAAC;AACb,YAAY,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE;AAC9D,gBAAgB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC;AACvC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,GAAG;AACb,QAAQ,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC5B,QAAQ,IAAI,EAAE,KAAK,IAAI,CAAC,GAAG,EAAE;AAC7B,YAAY,IAAI,CAAC,GAAG,EAAE,CAAC;AACvB,YAAY,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE;AAC7C,gBAAgB,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AACzC,YAAY,CAAC;AACb,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;AACzB,YAAY,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;AAC1B,QAAQ,CAAC;AACT,QAAQ,OAAO,EAAE,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACzF,IAAI,CAAC;AACL;;;;;"}
|
package/dist/id.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生成 RFC4122 版本 4 的 GUID/UUID。
|
|
3
|
+
* 收集来源:《基于mvc的javascript web富应用开发》 书中介绍是Robert Kieffer写的,还留了网址 http://goo.gl/0b0hu ,但实际访问不了。
|
|
4
|
+
* 格式:`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`
|
|
5
|
+
*
|
|
6
|
+
* @returns {string} 36 位大写 GUID
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // A2E0F340-6C3B-4D7F-B8C1-1E4F6A8B9C0D
|
|
10
|
+
* console.log(getGUID())
|
|
11
|
+
*/
|
|
12
|
+
function getGUID() {
|
|
13
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
14
|
+
let r = (Math.random() * 16) | 0,
|
|
15
|
+
v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
16
|
+
return v.toString(16).toUpperCase();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 分布式短 ID 生成器。
|
|
22
|
+
* 格式:`${timestamp}${flag}${serial}`,其中:
|
|
23
|
+
* - timestamp:毫秒级时间戳
|
|
24
|
+
* - flag:客户端标识串(自定义)
|
|
25
|
+
* - serial:同一毫秒内的序号,左补零到固定长度
|
|
26
|
+
*/
|
|
27
|
+
class MyId {
|
|
28
|
+
#ts = Date.now(); // 时间戳
|
|
29
|
+
#sn = 0; // 序号(保证同一客户端之间的唯一项)
|
|
30
|
+
#flag = ""; // 客户端标识(保证不同客户端之间的唯一项)
|
|
31
|
+
#len = 5; // 序号位长度(我的电脑测试,同一时间戳内可以for循环执行了1000次左右,没有一次超过3k,所以5位应该够用了)
|
|
32
|
+
// 测试代码
|
|
33
|
+
// let obj = {[Date.now()]:[]}; try { for (let i = 0; i < 100000; i++) { obj[Date.now()].push(i); } } catch { console.log(obj[Object.getOwnPropertyNames(obj)[0]].length); }
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {object} [option]
|
|
37
|
+
* @param {string} [option.flag] - 客户端标识,默认空串
|
|
38
|
+
* @param {number} [option.len=5] - 序号位长度(位数),安全范围 ≥0
|
|
39
|
+
*/
|
|
40
|
+
constructor(option = {}) {
|
|
41
|
+
if (option) {
|
|
42
|
+
if (typeof option.flag === "string") {
|
|
43
|
+
this.#flag = option.flag;
|
|
44
|
+
}
|
|
45
|
+
if (Number.isSafeInteger(option.len) && len >= 0) {
|
|
46
|
+
this.#len = option.len;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 生成下一个全局唯一字符串 ID。
|
|
53
|
+
* 同一毫秒序号自动递增;序号溢出时会在控制台警告。
|
|
54
|
+
* @returns {string}
|
|
55
|
+
*/
|
|
56
|
+
nextId() {
|
|
57
|
+
let ts = Date.now();
|
|
58
|
+
if (ts === this.#ts) {
|
|
59
|
+
this.#sn++;
|
|
60
|
+
if (this.#sn >= 10 ** this.#len) {
|
|
61
|
+
console.log("长度不够用了!!!");
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
this.#sn = 0;
|
|
65
|
+
this.#ts = ts;
|
|
66
|
+
}
|
|
67
|
+
return ts.toString() + this.#flag + this.#sn.toString().padStart(this.#len, "0");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { MyId, getGUID };
|
|
72
|
+
//# sourceMappingURL=id.js.map
|
package/dist/id.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sources":["../src/source/id.js"],"sourcesContent":["/**\r\n * 生成 RFC4122 版本 4 的 GUID/UUID。\r\n * 收集来源:《基于mvc的javascript web富应用开发》 书中介绍是Robert Kieffer写的,还留了网址 http://goo.gl/0b0hu ,但实际访问不了。\r\n * 格式:`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`\r\n *\r\n * @returns {string} 36 位大写 GUID\r\n *\r\n * @example\r\n * // A2E0F340-6C3B-4D7F-B8C1-1E4F6A8B9C0D\r\n * console.log(getGUID())\r\n */\r\nexport function getGUID() {\r\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\r\n let r = (Math.random() * 16) | 0,\r\n v = c == \"x\" ? r : (r & 0x3) | 0x8;\r\n return v.toString(16).toUpperCase();\r\n });\r\n}\r\n\r\n/**\r\n * 分布式短 ID 生成器。\r\n * 格式:`${timestamp}${flag}${serial}`,其中:\r\n * - timestamp:毫秒级时间戳\r\n * - flag:客户端标识串(自定义)\r\n * - serial:同一毫秒内的序号,左补零到固定长度\r\n */\r\nexport class MyId {\r\n #ts = Date.now(); //\t时间戳\r\n #sn = 0; //\t序号(保证同一客户端之间的唯一项)\r\n #flag = \"\"; //\t客户端标识(保证不同客户端之间的唯一项)\r\n #len = 5; //\t序号位长度(我的电脑测试,同一时间戳内可以for循环执行了1000次左右,没有一次超过3k,所以5位应该够用了)\r\n // 测试代码\r\n // let obj = {[Date.now()]:[]}; try { for (let i = 0; i < 100000; i++) { obj[Date.now()].push(i); } } catch { console.log(obj[Object.getOwnPropertyNames(obj)[0]].length); }\r\n\r\n /**\r\n * @param {object} [option]\r\n * @param {string} [option.flag] - 客户端标识,默认空串\r\n * @param {number} [option.len=5] - 序号位长度(位数),安全范围 ≥0\r\n */\r\n constructor(option = {}) {\r\n if (option) {\r\n if (typeof option.flag === \"string\") {\r\n this.#flag = option.flag;\r\n }\r\n if (Number.isSafeInteger(option.len) && len >= 0) {\r\n this.#len = option.len;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 生成下一个全局唯一字符串 ID。\r\n * 同一毫秒序号自动递增;序号溢出时会在控制台警告。\r\n * @returns {string}\r\n */\r\n nextId() {\r\n let ts = Date.now();\r\n if (ts === this.#ts) {\r\n this.#sn++;\r\n if (this.#sn >= 10 ** this.#len) {\r\n console.log(\"长度不够用了!!!\");\r\n }\r\n } else {\r\n this.#sn = 0;\r\n this.#ts = ts;\r\n }\r\n return ts.toString() + this.#flag + this.#sn.toString().padStart(this.#len, \"0\");\r\n }\r\n}\r\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,OAAO,GAAG;AAC1B,IAAI,OAAO,sCAAsC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK;AAC1E,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;AACxC,YAAY,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC;AAC/C,QAAQ,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAC5C,IAAI,CAAC,CAAC,CAAC;AACP,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,IAAI,CAAC;AAClB,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACrB,IAAI,GAAG,GAAG,CAAC,CAAC;AACZ,IAAI,KAAK,GAAG,EAAE,CAAC;AACf,IAAI,IAAI,GAAG,CAAC,CAAC;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,GAAG,EAAE,EAAE;AAC7B,QAAQ,IAAI,MAAM,EAAE;AACpB,YAAY,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE;AACjD,gBAAgB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC;AACzC,YAAY,CAAC;AACb,YAAY,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE;AAC9D,gBAAgB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC;AACvC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,GAAG;AACb,QAAQ,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC5B,QAAQ,IAAI,EAAE,KAAK,IAAI,CAAC,GAAG,EAAE;AAC7B,YAAY,IAAI,CAAC,GAAG,EAAE,CAAC;AACvB,YAAY,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE;AAC7C,gBAAgB,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AACzC,YAAY,CAAC;AACb,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;AACzB,YAAY,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;AAC1B,QAAQ,CAAC;AACT,QAAQ,OAAO,EAAE,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACzF,IAAI,CAAC;AACL;;;;"}
|
package/dist/timer.cjs
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 基于 `setTimeout` 的“间隔循环”定时器。
|
|
5
|
+
* 每次任务执行完成后才计算下一次间隔,避免任务堆积。
|
|
6
|
+
*/
|
|
7
|
+
class IntervalTimer {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 创建定时器实例。
|
|
11
|
+
* @param {() => void} fn - 每次间隔要执行的业务函数
|
|
12
|
+
* @param {number} [ms=1000] - 间隔时间(毫秒)
|
|
13
|
+
* @throws {TypeError} 当 `fn` 不是函数时抛出
|
|
14
|
+
*/
|
|
15
|
+
constructor(fn, ms = 1000) {
|
|
16
|
+
if (typeof fn !== "function") {
|
|
17
|
+
throw new TypeError("IntervalTimer: 必须传入一个函数");
|
|
18
|
+
}
|
|
19
|
+
this._fn = fn;
|
|
20
|
+
this._ms = ms;
|
|
21
|
+
this._timerId = null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 启动定时器;若已启动则先停止再重新启动。
|
|
26
|
+
* 首次执行会立即触发。
|
|
27
|
+
*/
|
|
28
|
+
start() {
|
|
29
|
+
this.stop();
|
|
30
|
+
const loop = () => {
|
|
31
|
+
this._fn(); // 执行业务
|
|
32
|
+
this._timerId = setTimeout(loop, this._ms);
|
|
33
|
+
};
|
|
34
|
+
loop(); // 立即执行第一次
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 停止定时器。
|
|
39
|
+
*/
|
|
40
|
+
stop() {
|
|
41
|
+
if (this._timerId !== null) {
|
|
42
|
+
clearTimeout(this._timerId);
|
|
43
|
+
this._timerId = null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 查询定时器是否正在运行。
|
|
49
|
+
* @returns {boolean}
|
|
50
|
+
*/
|
|
51
|
+
isRunning() {
|
|
52
|
+
return this._timerId !== null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exports.IntervalTimer = IntervalTimer;
|
|
57
|
+
//# sourceMappingURL=timer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timer.cjs","sources":["../src/source/timer.js"],"sourcesContent":["/**\n * 基于 `setTimeout` 的“间隔循环”定时器。\n * 每次任务执行完成后才计算下一次间隔,避免任务堆积。\n */\nexport class IntervalTimer {\n \n /**\n * 创建定时器实例。\n * @param {() => void} fn - 每次间隔要执行的业务函数\n * @param {number} [ms=1000] - 间隔时间(毫秒)\n * @throws {TypeError} 当 `fn` 不是函数时抛出\n */\n constructor(fn, ms = 1000) {\n if (typeof fn !== \"function\") {\n throw new TypeError(\"IntervalTimer: 必须传入一个函数\");\n }\n this._fn = fn;\n this._ms = ms;\n this._timerId = null;\n }\n\n /**\n * 启动定时器;若已启动则先停止再重新启动。\n * 首次执行会立即触发。\n */\n start() {\n this.stop();\n const loop = () => {\n this._fn(); // 执行业务\n this._timerId = setTimeout(loop, this._ms);\n };\n loop(); // 立即执行第一次\n }\n\n /**\n * 停止定时器。\n */\n stop() {\n if (this._timerId !== null) {\n clearTimeout(this._timerId);\n this._timerId = null;\n }\n }\n\n /**\n * 查询定时器是否正在运行。\n * @returns {boolean}\n */\n isRunning() {\n return this._timerId !== null;\n }\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACO,MAAM,aAAa,CAAC;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE;AAC/B,QAAQ,IAAI,OAAO,EAAE,KAAK,UAAU,EAAE;AACtC,YAAY,MAAM,IAAI,SAAS,CAAC,yBAAyB,CAAC;AAC1D,QAAQ;AACR,QAAQ,IAAI,CAAC,GAAG,GAAG,EAAE;AACrB,QAAQ,IAAI,CAAC,GAAG,GAAG,EAAE;AACrB,QAAQ,IAAI,CAAC,QAAQ,GAAG,IAAI;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,KAAK,GAAG;AACZ,QAAQ,IAAI,CAAC,IAAI,EAAE;AACnB,QAAQ,MAAM,IAAI,GAAG,MAAM;AAC3B,YAAY,IAAI,CAAC,GAAG,EAAE,CAAC;AACvB,YAAY,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;AACtD,QAAQ,CAAC;AACT,QAAQ,IAAI,EAAE,CAAC;AACf,IAAI;;AAEJ;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE;AACpC,YAAY,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC;AACvC,YAAY,IAAI,CAAC,QAAQ,GAAG,IAAI;AAChC,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,OAAO,IAAI,CAAC,QAAQ,KAAK,IAAI;AACrC,IAAI;AACJ;;;;"}
|
package/dist/timer.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 基于 `setTimeout` 的“间隔循环”定时器。
|
|
3
|
+
* 每次任务执行完成后才计算下一次间隔,避免任务堆积。
|
|
4
|
+
*/
|
|
5
|
+
class IntervalTimer {
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 创建定时器实例。
|
|
9
|
+
* @param {() => void} fn - 每次间隔要执行的业务函数
|
|
10
|
+
* @param {number} [ms=1000] - 间隔时间(毫秒)
|
|
11
|
+
* @throws {TypeError} 当 `fn` 不是函数时抛出
|
|
12
|
+
*/
|
|
13
|
+
constructor(fn, ms = 1000) {
|
|
14
|
+
if (typeof fn !== "function") {
|
|
15
|
+
throw new TypeError("IntervalTimer: 必须传入一个函数");
|
|
16
|
+
}
|
|
17
|
+
this._fn = fn;
|
|
18
|
+
this._ms = ms;
|
|
19
|
+
this._timerId = null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 启动定时器;若已启动则先停止再重新启动。
|
|
24
|
+
* 首次执行会立即触发。
|
|
25
|
+
*/
|
|
26
|
+
start() {
|
|
27
|
+
this.stop();
|
|
28
|
+
const loop = () => {
|
|
29
|
+
this._fn(); // 执行业务
|
|
30
|
+
this._timerId = setTimeout(loop, this._ms);
|
|
31
|
+
};
|
|
32
|
+
loop(); // 立即执行第一次
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 停止定时器。
|
|
37
|
+
*/
|
|
38
|
+
stop() {
|
|
39
|
+
if (this._timerId !== null) {
|
|
40
|
+
clearTimeout(this._timerId);
|
|
41
|
+
this._timerId = null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 查询定时器是否正在运行。
|
|
47
|
+
* @returns {boolean}
|
|
48
|
+
*/
|
|
49
|
+
isRunning() {
|
|
50
|
+
return this._timerId !== null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { IntervalTimer };
|
|
55
|
+
//# sourceMappingURL=timer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timer.js","sources":["../src/source/timer.js"],"sourcesContent":["/**\n * 基于 `setTimeout` 的“间隔循环”定时器。\n * 每次任务执行完成后才计算下一次间隔,避免任务堆积。\n */\nexport class IntervalTimer {\n \n /**\n * 创建定时器实例。\n * @param {() => void} fn - 每次间隔要执行的业务函数\n * @param {number} [ms=1000] - 间隔时间(毫秒)\n * @throws {TypeError} 当 `fn` 不是函数时抛出\n */\n constructor(fn, ms = 1000) {\n if (typeof fn !== \"function\") {\n throw new TypeError(\"IntervalTimer: 必须传入一个函数\");\n }\n this._fn = fn;\n this._ms = ms;\n this._timerId = null;\n }\n\n /**\n * 启动定时器;若已启动则先停止再重新启动。\n * 首次执行会立即触发。\n */\n start() {\n this.stop();\n const loop = () => {\n this._fn(); // 执行业务\n this._timerId = setTimeout(loop, this._ms);\n };\n loop(); // 立即执行第一次\n }\n\n /**\n * 停止定时器。\n */\n stop() {\n if (this._timerId !== null) {\n clearTimeout(this._timerId);\n this._timerId = null;\n }\n }\n\n /**\n * 查询定时器是否正在运行。\n * @returns {boolean}\n */\n isRunning() {\n return this._timerId !== null;\n }\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACO,MAAM,aAAa,CAAC;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE;AAC/B,QAAQ,IAAI,OAAO,EAAE,KAAK,UAAU,EAAE;AACtC,YAAY,MAAM,IAAI,SAAS,CAAC,yBAAyB,CAAC;AAC1D,QAAQ;AACR,QAAQ,IAAI,CAAC,GAAG,GAAG,EAAE;AACrB,QAAQ,IAAI,CAAC,GAAG,GAAG,EAAE;AACrB,QAAQ,IAAI,CAAC,QAAQ,GAAG,IAAI;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,KAAK,GAAG;AACZ,QAAQ,IAAI,CAAC,IAAI,EAAE;AACnB,QAAQ,MAAM,IAAI,GAAG,MAAM;AAC3B,YAAY,IAAI,CAAC,GAAG,EAAE,CAAC;AACvB,YAAY,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;AACtD,QAAQ,CAAC;AACT,QAAQ,IAAI,EAAE,CAAC;AACf,IAAI;;AAEJ;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE;AACpC,YAAY,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC;AACvC,YAAY,IAAI,CAAC,QAAQ,GAAG,IAAI;AAChC,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,OAAO,IAAI,CAAC,QAAQ,KAAK,IAAI;AACrC,IAAI;AACJ;;;;"}
|
package/dist/tree.cjs
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 把嵌套树拍平成 `{ [id]: node }` 映射,同时把原 `children` 置为 `null`。
|
|
5
|
+
*
|
|
6
|
+
* @template T extends Record<PropertyKey, any>
|
|
7
|
+
* @param {T[]} data - 嵌套树森林
|
|
8
|
+
* @param {string} [idKey='id'] - 主键字段
|
|
9
|
+
* @param {string} [childrenKey='children'] - 子节点字段
|
|
10
|
+
* @returns {Record<string, T & { [k in typeof childrenKey]: null }>} id→节点的映射表
|
|
11
|
+
*/
|
|
12
|
+
function nestedTree2IdMap(data, idKey = "id", childrenKey = "children") {
|
|
13
|
+
const retObj = {};
|
|
14
|
+
function fn(nodes) {
|
|
15
|
+
if (Array.isArray(nodes) && nodes.length > 0) {
|
|
16
|
+
nodes.forEach((node) => {
|
|
17
|
+
retObj[node[idKey]] = { ...node };
|
|
18
|
+
retObj[node[idKey]][childrenKey] = null;
|
|
19
|
+
|
|
20
|
+
fn(node[childrenKey]);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
fn(data);
|
|
25
|
+
return retObj;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 把**已包含完整父子关系**的扁平节点列表还原成嵌套树(森林)。
|
|
30
|
+
*
|
|
31
|
+
* @template T extends Record<PropertyKey, any>
|
|
32
|
+
* @param {T[]} nodes - 扁平节点列表(必须包含 id / parentId)
|
|
33
|
+
* @param {number | string} [parentId=0] - 根节点标识值
|
|
34
|
+
* @param {Object} [opts] - 字段映射配置
|
|
35
|
+
* @param {string} [opts.idKey='id'] - 节点主键
|
|
36
|
+
* @param {string} [opts.parentKey='parentId'] - 父节点外键
|
|
37
|
+
* @param {string} [opts.childrenKey='children'] - 存放子节点的字段
|
|
38
|
+
* @returns {(T & { [k in typeof childrenKey]: T[] })[]} 嵌套树森林
|
|
39
|
+
*/
|
|
40
|
+
function flatCompleteTree2NestedTree(nodes, parentId = 0, { idKey = "id", parentKey = "parentId", childrenKey = "children" } = {}) {
|
|
41
|
+
const map = new Map(); // id -> node
|
|
42
|
+
const items = []; // 多根森林
|
|
43
|
+
|
|
44
|
+
// 1. 初始化:保证每个节点都有 children,并存入 map
|
|
45
|
+
for (const item of nodes) {
|
|
46
|
+
const node = { ...item, [childrenKey]: [] };
|
|
47
|
+
map.set(item[idKey], node);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 2. 建立父子关系
|
|
51
|
+
for (const item of nodes) {
|
|
52
|
+
const node = map.get(item[idKey]);
|
|
53
|
+
const parentIdVal = item[parentKey];
|
|
54
|
+
|
|
55
|
+
if (parentIdVal === parentId) {
|
|
56
|
+
// 根层
|
|
57
|
+
items.push(node);
|
|
58
|
+
} else {
|
|
59
|
+
// 非根层:找到父节点,把自己挂上去
|
|
60
|
+
const parent = map.get(parentIdVal);
|
|
61
|
+
if (parent) parent[childrenKey].push(node);
|
|
62
|
+
// 如果 parent 不存在,说明数据不完整,可自定义处理
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return items;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 在嵌套树中按 `id` 递归查找节点,并返回其指定属性值。
|
|
71
|
+
*
|
|
72
|
+
* @template T extends Record<PropertyKey, any>
|
|
73
|
+
* @param {string | number} id - 要查找的 id
|
|
74
|
+
* @param {T[]} arr - 嵌套树森林
|
|
75
|
+
* @param {string} [resultKey='name'] - 需要返回的字段
|
|
76
|
+
* @param {string} [idKey='id'] - 主键字段
|
|
77
|
+
* @param {string} [childrenKey='children'] - 子节点字段
|
|
78
|
+
* @returns {any} 找到的值;未找到返回 `undefined`
|
|
79
|
+
*/
|
|
80
|
+
const findObjAttrValueById = function findObjAttrValueByIdFn(id, arr, resultKey = "name", idKey = "id", childrenKey = "children") {
|
|
81
|
+
if (Array.isArray(arr) && arr.length > 0) {
|
|
82
|
+
for (let i = 0; i < arr.length; i++) {
|
|
83
|
+
const item = arr[i];
|
|
84
|
+
if (item[idKey]?.toString() === id?.toString()) {
|
|
85
|
+
return item[resultKey];
|
|
86
|
+
} else if (Array.isArray(item[childrenKey]) && item[childrenKey].length > 0) {
|
|
87
|
+
const result = findObjAttrValueByIdFn(id, item[childrenKey], resultKey, idKey, childrenKey);
|
|
88
|
+
if (result) {
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
exports.findObjAttrValueById = findObjAttrValueById;
|
|
97
|
+
exports.flatCompleteTree2NestedTree = flatCompleteTree2NestedTree;
|
|
98
|
+
exports.nestedTree2IdMap = nestedTree2IdMap;
|
|
99
|
+
//# sourceMappingURL=tree.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.cjs","sources":["../src/source/tree.js"],"sourcesContent":["/**\n * 把嵌套树拍平成 `{ [id]: node }` 映射,同时把原 `children` 置为 `null`。\n *\n * @template T extends Record<PropertyKey, any>\n * @param {T[]} data - 嵌套树森林\n * @param {string} [idKey='id'] - 主键字段\n * @param {string} [childrenKey='children'] - 子节点字段\n * @returns {Record<string, T & { [k in typeof childrenKey]: null }>} id→节点的映射表\n */\nexport function nestedTree2IdMap(data, idKey = \"id\", childrenKey = \"children\") {\n const retObj = {};\n function fn(nodes) {\n if (Array.isArray(nodes) && nodes.length > 0) {\n nodes.forEach((node) => {\n retObj[node[idKey]] = { ...node };\n retObj[node[idKey]][childrenKey] = null;\n\n fn(node[childrenKey]);\n });\n }\n }\n fn(data);\n return retObj;\n}\n\n/**\n * 把**已包含完整父子关系**的扁平节点列表还原成嵌套树(森林)。\n *\n * @template T extends Record<PropertyKey, any>\n * @param {T[]} nodes - 扁平节点列表(必须包含 id / parentId)\n * @param {number | string} [parentId=0] - 根节点标识值\n * @param {Object} [opts] - 字段映射配置\n * @param {string} [opts.idKey='id'] - 节点主键\n * @param {string} [opts.parentKey='parentId'] - 父节点外键\n * @param {string} [opts.childrenKey='children'] - 存放子节点的字段\n * @returns {(T & { [k in typeof childrenKey]: T[] })[]} 嵌套树森林\n */\nexport function flatCompleteTree2NestedTree(nodes, parentId = 0, { idKey = \"id\", parentKey = \"parentId\", childrenKey = \"children\" } = {}) {\n const map = new Map(); // id -> node\n const items = []; // 多根森林\n\n // 1. 初始化:保证每个节点都有 children,并存入 map\n for (const item of nodes) {\n const node = { ...item, [childrenKey]: [] };\n map.set(item[idKey], node);\n }\n\n // 2. 建立父子关系\n for (const item of nodes) {\n const node = map.get(item[idKey]);\n const parentIdVal = item[parentKey];\n\n if (parentIdVal === parentId) {\n // 根层\n items.push(node);\n } else {\n // 非根层:找到父节点,把自己挂上去\n const parent = map.get(parentIdVal);\n if (parent) parent[childrenKey].push(node);\n // 如果 parent 不存在,说明数据不完整,可自定义处理\n }\n }\n\n return items;\n}\n\n/**\n * 在嵌套树中按 `id` 递归查找节点,并返回其指定属性值。\n *\n * @template T extends Record<PropertyKey, any>\n * @param {string | number} id - 要查找的 id\n * @param {T[]} arr - 嵌套树森林\n * @param {string} [resultKey='name'] - 需要返回的字段\n * @param {string} [idKey='id'] - 主键字段\n * @param {string} [childrenKey='children'] - 子节点字段\n * @returns {any} 找到的值;未找到返回 `undefined`\n */\nexport const findObjAttrValueById = function findObjAttrValueByIdFn(id, arr, resultKey = \"name\", idKey = \"id\", childrenKey = \"children\") {\n if (Array.isArray(arr) && arr.length > 0) {\n for (let i = 0; i < arr.length; i++) {\n const item = arr[i];\n if (item[idKey]?.toString() === id?.toString()) {\n return item[resultKey];\n } else if (Array.isArray(item[childrenKey]) && item[childrenKey].length > 0) {\n const result = findObjAttrValueByIdFn(id, item[childrenKey], resultKey, idKey, childrenKey);\n if (result) {\n return result;\n }\n }\n }\n }\n};\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,WAAW,GAAG,UAAU,EAAE;AAC/E,IAAI,MAAM,MAAM,GAAG,EAAE;AACrB,IAAI,SAAS,EAAE,CAAC,KAAK,EAAE;AACvB,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AACtD,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK;AACpC,gBAAgB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE;AACjD,gBAAgB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,IAAI;;AAEvD,gBAAgB,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AACrC,YAAY,CAAC,CAAC;AACd,QAAQ;AACR,IAAI;AACJ,IAAI,EAAE,CAAC,IAAI,CAAC;AACZ,IAAI,OAAO,MAAM;AACjB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,2BAA2B,CAAC,KAAK,EAAE,QAAQ,GAAG,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI,EAAE,SAAS,GAAG,UAAU,EAAE,WAAW,GAAG,UAAU,EAAE,GAAG,EAAE,EAAE;AAC1I,IAAI,MAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;AAC1B,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;;AAErB;AACA,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AAC9B,QAAQ,MAAM,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC,WAAW,GAAG,EAAE,EAAE;AACnD,QAAQ,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;AAClC,IAAI;;AAEJ;AACA,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AAC9B,QAAQ,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACzC,QAAQ,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC;;AAE3C,QAAQ,IAAI,WAAW,KAAK,QAAQ,EAAE;AACtC;AACA,YAAY,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5B,QAAQ,CAAC,MAAM;AACf;AACA,YAAY,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;AAC/C,YAAY,IAAI,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;AACtD;AACA,QAAQ;AACR,IAAI;;AAEJ,IAAI,OAAO,KAAK;AAChB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,oBAAoB,GAAG,SAAS,sBAAsB,CAAC,EAAE,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,EAAE,KAAK,GAAG,IAAI,EAAE,WAAW,GAAG,UAAU,EAAE;AACzI,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE;AAC9C,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC7C,YAAY,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;AAC/B,YAAY,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE;AAC5D,gBAAgB,OAAO,IAAI,CAAC,SAAS,CAAC;AACtC,YAAY,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AACzF,gBAAgB,MAAM,MAAM,GAAG,sBAAsB,CAAC,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,CAAC;AAC3G,gBAAgB,IAAI,MAAM,EAAE;AAC5B,oBAAoB,OAAO,MAAM;AACjC,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,IAAI;AACJ;;;;;;"}
|