@ybgnb/utils 0.1.5 → 0.1.6

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/index.d.ts CHANGED
@@ -78,11 +78,6 @@ export declare type FunctionKeys<T> = {
78
78
  [K in keyof T]: T[K] extends AnyFn ? K : never;
79
79
  }[keyof T];
80
80
 
81
- /**
82
- * 生成唯一 id
83
- */
84
- export declare function generateId(): string;
85
-
86
81
  /**
87
82
  * 获取异常信息
88
83
  */
package/dist/index.js CHANGED
@@ -1,31 +1,30 @@
1
- import { nanoid as e } from "nanoid";
2
- import t from "dayjs";
1
+ import e from "dayjs";
3
2
  //#region src/utils/error.ts
4
- function n(e) {
5
- return e instanceof o;
3
+ function t(e) {
4
+ return e instanceof a;
6
5
  }
7
- function r(e, t) {
6
+ function n(e, t) {
8
7
  return t && (e.message = `${t} ${e.message}`), e;
9
8
  }
10
- function i(e, t) {
11
- return n(e) ? r(e, t) : typeof e == "object" && e && "message" in e && typeof e.message == "string" ? r(new o(e.message), t) : r(new o(String(e)), t);
9
+ function r(e, r) {
10
+ return t(e) ? n(e, r) : typeof e == "object" && e && "message" in e && typeof e.message == "string" ? n(new a(e.message), r) : n(new a(String(e)), r);
12
11
  }
13
- function a(e) {
14
- return i(e).message;
12
+ function i(e) {
13
+ return r(e).message;
15
14
  }
16
15
  //#endregion
17
16
  //#region src/common/error.ts
18
- var o = class extends Error {
17
+ var a = class extends Error {
19
18
  message;
20
19
  rawError;
21
20
  constructor(e, t) {
22
- super(e), this.message = t ? `${e} ${a(t)}` : e, this.rawError = t;
21
+ super(e), this.message = t ? `${e} ${i(t)}` : e, this.rawError = t;
23
22
  }
24
- }, s = class extends o {
23
+ }, o = class extends a {
25
24
  constructor() {
26
25
  super("操作已取消");
27
26
  }
28
- }, c = class e {
27
+ }, s = class e {
29
28
  success;
30
29
  msg;
31
30
  data;
@@ -39,25 +38,25 @@ var o = class extends Error {
39
38
  return new e(!1, t, n);
40
39
  }
41
40
  static createError(t) {
42
- return new e(!1, a(t));
41
+ return new e(!1, i(t));
43
42
  }
44
43
  async toPromise() {
45
44
  if (this.success) return this.data;
46
- throw new o(this.msg);
45
+ throw new a(this.msg);
47
46
  }
48
- }, l = async (e) => {
47
+ }, c = async (e) => {
49
48
  try {
50
- return c.createSuccess(await e());
49
+ return s.createSuccess(await e());
51
50
  } catch (e) {
52
- return c.createError(e);
51
+ return s.createError(e);
53
52
  }
54
53
  };
55
54
  //#endregion
56
55
  //#region src/utils/array.ts
57
- function u(e) {
56
+ function l(e) {
58
57
  return Array.isArray(e) && e.length === 0;
59
58
  }
60
- function d(e, t) {
59
+ function u(e, t) {
61
60
  if (!Number.isInteger(t) || t < 1) throw Error("size 必须是正整数");
62
61
  let n = [];
63
62
  for (let r = 0; r < e.length; r += t) n.push(e.slice(r, r + t));
@@ -65,7 +64,7 @@ function d(e, t) {
65
64
  }
66
65
  //#endregion
67
66
  //#region src/utils/function.ts
68
- function f(e, t) {
67
+ function d(e, t) {
69
68
  t ??= e.length;
70
69
  let n = Math.floor(Math.random() * t) + 1, r = [...e];
71
70
  for (let e = r.length - 1; e > 0; e--) {
@@ -75,7 +74,7 @@ function f(e, t) {
75
74
  let i = r.slice(0, n);
76
75
  for (let e of i) e();
77
76
  }
78
- async function p(e, t, n, r) {
77
+ async function f(e, t, n, r) {
79
78
  for (let i = e; i <= t; i += n) {
80
79
  let e = t - i + 1, a = Math.min(n, e);
81
80
  await r(Array.from({ length: a }, (e, t) => i + t));
@@ -83,7 +82,7 @@ async function p(e, t, n, r) {
83
82
  }
84
83
  //#endregion
85
84
  //#region src/utils/github.ts
86
- function m(e) {
85
+ function p(e) {
87
86
  e = e.replace(/^git\+/, "");
88
87
  let t = /^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git|\/)?$/, n = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)$/, r = e.match(t);
89
88
  if (r) return {
@@ -97,21 +96,16 @@ function m(e) {
97
96
  repo: i[2],
98
97
  branch: i[3]
99
98
  };
100
- throw new o("解析插件仓库URL失败");
101
- }
102
- //#endregion
103
- //#region src/utils/id.ts
104
- function h() {
105
- return e();
99
+ throw new a("解析插件仓库URL失败");
106
100
  }
107
101
  //#endregion
108
102
  //#region src/utils/network.ts
109
- function g(e) {
103
+ function m(e) {
110
104
  return typeof e == "object" && !!e && "downlink" in e && "rtt" in e && "effectiveType" in e;
111
105
  }
112
- function _() {
106
+ function h() {
113
107
  if (!navigator.onLine) return "offline";
114
- if ("connection" in navigator && g(navigator.connection)) {
108
+ if ("connection" in navigator && m(navigator.connection)) {
115
109
  let e = navigator.connection;
116
110
  return {
117
111
  downlink: e.downlink,
@@ -120,11 +114,11 @@ function _() {
120
114
  };
121
115
  } else return "online";
122
116
  }
123
- function v(e) {
117
+ function g(e) {
124
118
  let t = () => {
125
- e(_());
119
+ e(h());
126
120
  };
127
- if ("connection" in navigator && g(navigator.connection)) {
121
+ if ("connection" in navigator && m(navigator.connection)) {
128
122
  let e = navigator.connection;
129
123
  return e.addEventListener("change", t), () => e.removeEventListener("change", t);
130
124
  } else return window.addEventListener("online", t), window.addEventListener("offline", t), () => {
@@ -133,7 +127,7 @@ function v(e) {
133
127
  }
134
128
  //#endregion
135
129
  //#region src/utils/random.ts
136
- function y(e) {
130
+ function _(e) {
137
131
  let t = e.slice();
138
132
  for (let e = t.length - 1; e > 0; e--) {
139
133
  let n = Math.floor(Math.random() * (e + 1));
@@ -141,32 +135,32 @@ function y(e) {
141
135
  }
142
136
  return t;
143
137
  }
144
- function b(e, t) {
138
+ function v(e, t) {
145
139
  return Math.floor(Math.random() * (t - e + 1)) + e;
146
140
  }
147
- function x(e, t) {
141
+ function y(e, t) {
148
142
  return Math.random() * (t - e) + e;
149
143
  }
150
- function S(e, t) {
151
- return y(e).slice(0, t);
144
+ function b(e, t) {
145
+ return _(e).slice(0, t);
152
146
  }
153
- function C(e, t) {
147
+ function x(e, t) {
154
148
  let n = [];
155
149
  for (let r = 0; r < t; r++) {
156
- let t = b(0, e.length - 1);
150
+ let t = v(0, e.length - 1);
157
151
  n.push(e[t]);
158
152
  }
159
153
  return n;
160
154
  }
161
- function w(e) {
162
- return e[b(0, e.length - 1)];
155
+ function S(e) {
156
+ return e[v(0, e.length - 1)];
163
157
  }
164
- function T(e) {
165
- return b(1, e);
158
+ function C(e) {
159
+ return v(1, e);
166
160
  }
167
161
  //#endregion
168
162
  //#region src/utils/sleep.ts
169
- function E(e, t) {
163
+ function w(e, t) {
170
164
  return new Promise((n, r) => {
171
165
  if (t?.aborted) return r(/* @__PURE__ */ Error("取消操作"));
172
166
  let i = setTimeout(() => {
@@ -179,24 +173,24 @@ function E(e, t) {
179
173
  t?.addEventListener("abort", a);
180
174
  });
181
175
  }
182
- function D(e, t, n) {
183
- return E(Math.random() * (t - e) + e, n);
176
+ function T(e, t, n) {
177
+ return w(Math.random() * (t - e) + e, n);
184
178
  }
185
179
  //#endregion
186
180
  //#region src/utils/time.ts
187
- function O(e) {
188
- return t(e).format("YYYY-MM-DD HH:mm:ss");
181
+ function E(t) {
182
+ return e(t).format("YYYY-MM-DD HH:mm:ss");
189
183
  }
190
- function k(e) {
191
- return t(e).format("YYYY-MM-DD");
184
+ function D(t) {
185
+ return e(t).format("YYYY-MM-DD");
192
186
  }
193
- function A(e) {
194
- return t(e).format("HH:mm:ss");
187
+ function O(t) {
188
+ return e(t).format("HH:mm:ss");
195
189
  }
196
190
  //#endregion
197
191
  //#region src/utils/url.ts
198
- var j = /[!'()*]/g;
199
- function M(e) {
192
+ var k = /[!'()*]/g;
193
+ function A(e) {
200
194
  try {
201
195
  let t = new URL(e);
202
196
  return t.protocol === "http:" || t.protocol === "https:";
@@ -204,7 +198,7 @@ function M(e) {
204
198
  return !1;
205
199
  }
206
200
  }
207
- function N(e) {
201
+ function j(e) {
208
202
  try {
209
203
  let { origin: t, pathname: n, searchParams: r } = new URL(e);
210
204
  return {
@@ -215,15 +209,15 @@ function N(e) {
215
209
  throw Error("Invalid URL");
216
210
  }
217
211
  }
218
- function P(e) {
212
+ function M(e) {
219
213
  return Object.keys(e).sort().map((t) => {
220
214
  let n = e[t];
221
215
  if (n == null) return "";
222
- let r = String(n).replace(j, "");
216
+ let r = String(n).replace(k, "");
223
217
  return `${encodeURIComponent(t)}=${encodeURIComponent(r)}`;
224
218
  }).join("&");
225
219
  }
226
- function F(e, t) {
220
+ function N(e, t) {
227
221
  let n = {};
228
222
  return e.size > 0 && e.forEach((e, t) => {
229
223
  n[t] = e;
@@ -234,16 +228,16 @@ function F(e, t) {
234
228
  }
235
229
  //#endregion
236
230
  //#region src/utils/dom/color.ts
237
- var I = (e, t, n, r = "srgb", i) => `color-mix(in ${r}, ${e} ${n}%, ${t} ${i || 100 - n}%)`, L = (e) => ({
231
+ var P = (e, t, n, r = "srgb", i) => `color-mix(in ${r}, ${e} ${n}%, ${t} ${i || 100 - n}%)`, F = (e) => ({
238
232
  r: parseInt(e.slice(1, 3), 16),
239
233
  g: parseInt(e.slice(3, 5), 16),
240
234
  b: parseInt(e.slice(5, 7), 16)
241
- }), R = (e, t) => {
235
+ }), I = (e, t) => {
242
236
  document.documentElement.style.setProperty(e, t);
243
237
  };
244
238
  //#endregion
245
239
  //#region src/utils/dom/img.ts
246
- function z(e) {
240
+ function L(e) {
247
241
  return new Promise((t, n) => {
248
242
  if (e.dataset.state === "loading" && (e.src = e.dataset.src), e.complete && e.naturalWidth > 0) {
249
243
  t(e);
@@ -259,7 +253,7 @@ function z(e) {
259
253
  e.addEventListener("load", r), e.addEventListener("error", i);
260
254
  });
261
255
  }
262
- async function B(e, t = "image/png") {
256
+ async function R(e, t = "image/png") {
263
257
  let n = document.createElement("canvas");
264
258
  n.width = e.naturalWidth, n.height = e.naturalHeight;
265
259
  let r = n.getContext("2d");
@@ -268,12 +262,12 @@ async function B(e, t = "image/png") {
268
262
  n.toBlob((t) => t ? e(t) : r(/* @__PURE__ */ Error("toBlob 失败")), t);
269
263
  })).arrayBuffer();
270
264
  }
271
- async function V(e, t) {
272
- return await B(await z(e), t);
265
+ async function z(e, t) {
266
+ return await R(await L(e), t);
273
267
  }
274
268
  //#endregion
275
269
  //#region src/utils/dom/page.ts
276
- function H(e) {
270
+ function B(e) {
277
271
  let t, n;
278
272
  if (document.hidden === void 0 ? "msHidden" in document && document.msHidden !== void 0 ? (t = "msHidden", n = "msvisibilitychange") : "webkitHidden" in document && document.webkitHidden !== void 0 && (t = "webkitHidden", n = "webkitvisibilitychange") : (t = "hidden", n = "visibilitychange"), !t || !n) return null;
279
273
  let r = () => {
@@ -285,14 +279,14 @@ function H(e) {
285
279
  }
286
280
  //#endregion
287
281
  //#region src/utils/dom/scroll.ts
288
- async function U(e) {
282
+ async function V(e) {
289
283
  if (!e) return;
290
284
  let t = e.getBoundingClientRect(), n = document.documentElement, r = document.body, i = window.scrollX || n.scrollLeft || r.scrollLeft, a = window.scrollY || n.scrollTop || r.scrollTop, o = window.innerWidth, s = window.innerHeight, c = t.left + i + t.width / 2 - o / 2, l = t.top + a + t.height / 2 - s / 2, u = Math.max(0, r.scrollWidth - o), d = Math.max(0, r.scrollHeight - s);
291
285
  if (u === 0 && d === 0) return;
292
286
  let f = u > 0 ? Math.min(Math.max(c, 0), u) : i, p = d > 0 ? Math.min(Math.max(l, 0), d) : a, m = Math.abs(window.scrollX - f) > 1, h = Math.abs(window.scrollY - p) > 1;
293
- !m && !h || await G(f, p);
287
+ !m && !h || await U(f, p);
294
288
  }
295
- function W(e, t) {
289
+ function H(e, t) {
296
290
  return new Promise((n) => {
297
291
  let r = window.scrollX, i = window.scrollY;
298
292
  if (Math.abs(r - e) < 1 && Math.abs(i - t) < 1) {
@@ -319,7 +313,7 @@ function W(e, t) {
319
313
  });
320
314
  });
321
315
  }
322
- async function G(e, t) {
316
+ async function U(e, t) {
323
317
  return new Promise((n) => {
324
318
  let r = window.scrollX, i = window.scrollY;
325
319
  async function a() {
@@ -329,7 +323,7 @@ async function G(e, t) {
329
323
  return;
330
324
  }
331
325
  let c = Math.sign(o) * Math.min(Math.max(2, Math.random() * Math.abs(o) * .2), Math.abs(o)), l = Math.sign(s) * Math.min(Math.max(2, Math.random() * Math.abs(s) * .2), Math.abs(s));
332
- r += c, i += l, await W(r, i);
326
+ r += c, i += l, await H(r, i);
333
327
  let u = 10 + Math.random() * 20;
334
328
  setTimeout(a, u);
335
329
  }
@@ -337,6 +331,6 @@ async function G(e, t) {
337
331
  });
338
332
  }
339
333
  //#endregion
340
- export { s as AbortError, c as BizResult, o as CommonError, d as chunk, i as convertToCommonError, P as encodeURLParams, l as execBiz, h as generateId, a as getErrorMessage, k as getFormattedDate, O as getFormattedDateTime, A as getFormattedTime, B as getImageArrayBuffer, V as getImgArrayBufferAfterLoad, _ as getNetworkInfo, L as hexToRgb, U as humanScrollElIntoCenter, G as humanScrollTo, j as invalidCharRegex, n as isCommonError, u as isEmptyArr, M as isHttpUrl, F as mergeQueryParams, I as mixColor, v as onNetworkChange, H as onVisibilityChange, m as parseGithubRepo, N as parseUrl, r as prependErrorMessage, p as processRangeInBatches, T as random1ToN, x as randomFloat, b as randomInt, f as runRandomFunctions, S as sample, w as sampleOne, C as sampleWithReplacement, R as setCssVar, y as shuffle, E as sleep, D as sleepRandom, W as waitScrollTo, z as whenImageLoaded };
334
+ export { o as AbortError, s as BizResult, a as CommonError, u as chunk, r as convertToCommonError, M as encodeURLParams, c as execBiz, i as getErrorMessage, D as getFormattedDate, E as getFormattedDateTime, O as getFormattedTime, R as getImageArrayBuffer, z as getImgArrayBufferAfterLoad, h as getNetworkInfo, F as hexToRgb, V as humanScrollElIntoCenter, U as humanScrollTo, k as invalidCharRegex, t as isCommonError, l as isEmptyArr, A as isHttpUrl, N as mergeQueryParams, P as mixColor, g as onNetworkChange, B as onVisibilityChange, p as parseGithubRepo, j as parseUrl, n as prependErrorMessage, f as processRangeInBatches, C as random1ToN, y as randomFloat, v as randomInt, d as runRandomFunctions, b as sample, S as sampleOne, x as sampleWithReplacement, I as setCssVar, _ as shuffle, w as sleep, T as sleepRandom, H as waitScrollTo, L as whenImageLoaded };
341
335
 
342
336
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/utils/error.ts","../src/common/error.ts","../src/common/biz-result.ts","../src/utils/array.ts","../src/utils/function.ts","../src/utils/github.ts","../src/utils/id.ts","../src/utils/network.ts","../src/utils/random.ts","../src/utils/sleep.ts","../src/utils/time.ts","../src/utils/url.ts","../src/utils/dom/color.ts","../src/utils/dom/css.ts","../src/utils/dom/img.ts","../src/utils/dom/page.ts","../src/utils/dom/scroll.ts"],"sourcesContent":["import { CommonError } from '../common/error.js'\n\n/**\n * 判断是否为通用异常\n */\nexport function isCommonError(error: unknown): error is CommonError {\n return error instanceof CommonError\n}\n\n/**\n * 设置异常信息的前置提示\n * @param error 异常\n * @param preMsg 前置信息 `${preMsg}${error.message}`\n */\nexport function prependErrorMessage(error: CommonError, preMsg?: string): CommonError {\n if (preMsg) {\n error.message = `${preMsg} ${error.message}`\n }\n return error\n}\n\n/**\n * 转换到通用异常\n * @param error 异常\n * @param preMsg 前置提示 `${preMsg}${error.message}`\n */\nexport function convertToCommonError(error: unknown, preMsg?: string): CommonError {\n if (isCommonError(error)) {\n return prependErrorMessage(error, preMsg)\n }\n if (\n typeof error === 'object' &&\n error !== null &&\n 'message' in error &&\n typeof (error as Record<string, unknown>).message === 'string'\n ) {\n const newError = error as { message: string }\n return prependErrorMessage(new CommonError(newError.message), preMsg)\n } else {\n // 如果抛出的异常不是object\n return prependErrorMessage(new CommonError(String(error)), preMsg)\n }\n}\n\n/**\n * 获取异常信息\n */\nexport function getErrorMessage(error: unknown): string {\n return convertToCommonError(error).message\n}\n","import { getErrorMessage } from '../utils/error.js'\n\n/**\n * 通用异常\n */\nexport class CommonError extends Error {\n // 异常信息\n message: string\n // 原始异常\n rawError?: Error\n\n constructor(message: string, rawError?: Error) {\n super(message)\n this.message = rawError ? `${message} ${getErrorMessage(rawError)}` : message\n this.rawError = rawError\n }\n}\n\n/**\n * 中止异常\n */\nexport class AbortError extends CommonError {\n constructor() {\n super('操作已取消')\n }\n}\n","import { CommonError } from './error.js'\nimport { getErrorMessage } from '../utils/error.js'\n\n/**\n * 业务执行结果\n */\nexport class BizResult<T> {\n success: boolean\n msg: string\n data?: T\n\n constructor(success: boolean, msg: string, data?: T) {\n this.success = success\n this.msg = msg\n this.data = data\n }\n\n static createSuccess<T>(data: T) {\n return new BizResult(true, '操作成功', data)\n }\n\n static createFail<T>(msg: string = '操作失败', data?: T) {\n return new BizResult(false, msg, data)\n }\n\n static createError<T>(e: unknown) {\n return new BizResult<T>(false, getErrorMessage(e))\n }\n\n /**\n * 展开成Promise\n */\n async toPromise(): Promise<void>\n async toPromise<T>(): Promise<T>\n async toPromise<T = void>(): Promise<T> {\n if (this.success) {\n return this.data as T\n } else {\n throw new CommonError(this.msg)\n }\n }\n}\n\n/**\n * 执行业务(自动包裹BuResult)\n * @param run 执行方法\n */\nexport const execBiz = async <T>(run: () => Promise<T>): Promise<BizResult<T>> => {\n try {\n return BizResult.createSuccess<T>(await run())\n } catch (e) {\n return BizResult.createError(e)\n }\n}\n","/**\n * 是否为空数组\n * @param data\n */\nexport function isEmptyArr(data: unknown) {\n return Array.isArray(data) && data.length === 0\n}\n\n/**\n * 将数组分块为指定大小的多个子数组\n * @param arr 原数组\n * @param size 每个块的长度\n * @example chunk([1,2,3,4,5], 2) => [[1,2],[3,4],[5]]\n */\nexport function chunk<T>(arr: T[], size: number): T[][] {\n if (!Number.isInteger(size) || size < 1) throw new Error('size 必须是正整数')\n const result: T[][] = []\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size))\n }\n return result\n}\n","/**\n * 随机运行参数\n * @param fns\n * @param maxCount 最多执行次数(1 ~ fns.length)\n */\nexport function runRandomFunctions(fns: Array<() => void>, maxCount?: number): void {\n maxCount = maxCount ?? fns.length\n const count = Math.floor(Math.random() * maxCount) + 1\n\n const shuffled = [...fns]\n for (let i = shuffled.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]\n }\n\n const selected = shuffled.slice(0, count)\n\n for (const fn of selected) {\n fn()\n }\n}\n\n/**\n * 将数字范围按批次处理,每个批次调用一次异步函数\n *\n * @param start - 起始值(包含)\n * @param end - 结束值(包含)\n * @param batchSize - 每批最大元素个数\n * @param processor - 处理单批数字数组的异步函数\n *\n * @example\n * // 分批处理 1..10,每批最多 3 个数字\n * await processRangeInBatches(1, 10, 3, async (batch) => {\n * console.log(batch) // 输出: [1,2,3], [4,5,6], [7,8,9], [10]\n * })\n */\nexport async function processRangeInBatches(\n start: number,\n end: number,\n batchSize: number,\n processor: (batch: number[]) => Promise<void>,\n): Promise<void> {\n for (let current = start; current <= end; current += batchSize) {\n const remaining = end - current + 1\n const actualSize = Math.min(batchSize, remaining)\n const batch = Array.from({ length: actualSize }, (_, idx) => current + idx)\n\n await processor(batch)\n }\n}\n","import { CommonError } from '../common/error.js'\nimport type { GithubRepository } from '../types/github.js'\n\n/**\n * 从 url 解析 github 仓库信息\n * @param repositoryUrl 仓库 URL(支持带有git+前缀、具体文件路径)\n */\nexport function parseGithubRepo(repositoryUrl: string): GithubRepository {\n // 去掉 git+ 前缀\n repositoryUrl = repositoryUrl.replace(/^git\\+/, '')\n\n const regexBase = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+?)(?:\\.git|\\/)?$/\n const regexFile = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)\\/blob\\/([^/]+)$/\n\n // 情况 1:git clone 地址 或 repo 根路径\n const m1 = repositoryUrl.match(regexBase)\n if (m1) {\n return {\n owner: m1[1],\n repo: m1[2],\n branch: 'main', // 默认分支 main\n }\n }\n\n // 情况 2:具体文件路径\n const m2 = repositoryUrl.match(regexFile)\n if (m2) {\n return {\n owner: m2[1],\n repo: m2[2],\n branch: m2[3],\n }\n }\n\n throw new CommonError('解析插件仓库URL失败')\n}\n","import { nanoid } from 'nanoid'\n\n/**\n * 生成唯一 id\n */\nexport function generateId(): string {\n return nanoid()\n}\n","import type { NetworkInfo, NetworkState } from '../types/network.js'\n\nfunction isConnection(obj: unknown): obj is NetworkInfo {\n return obj !== null && typeof obj === 'object' && 'downlink' in obj && 'rtt' in obj && 'effectiveType' in obj\n}\n\n/**\n * 获取网络信息\n */\nexport function getNetworkInfo(): NetworkState {\n if (!navigator.onLine) {\n return 'offline'\n }\n\n if ('connection' in navigator && isConnection(navigator.connection)) {\n // 现代 Web API 直接获取网络连接的信息\n const connection = navigator.connection\n return {\n downlink: connection.downlink,\n rtt: connection.rtt,\n effectiveType: connection.effectiveType,\n }\n } else {\n return 'online'\n }\n}\n\n/**\n * 监听网络状态变化\n * @param listener 监听器\n * @returns 成功监听时返回解绑函数\n */\nexport function onNetworkChange(listener: (info: NetworkState) => void) {\n const handleChange = () => {\n listener(getNetworkInfo())\n }\n\n if ('connection' in navigator && isConnection(navigator.connection)) {\n // 现代 Web API\n const connection = navigator.connection\n connection.addEventListener('change', handleChange)\n return () => connection.removeEventListener('change', handleChange)\n } else {\n window.addEventListener('online', handleChange)\n window.addEventListener('offline', handleChange)\n return () => {\n window.removeEventListener('online', handleChange)\n window.removeEventListener('offline', handleChange)\n }\n }\n}\n","/**\n * 数组洗牌\n */\nexport function shuffle<T>(arr: T[]): T[] {\n const clone = arr.slice()\n for (let i = clone.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[clone[i], clone[j]] = [clone[j], clone[i]]\n }\n return clone\n}\n\n/**\n * 获取 [min, max] 的随机整数\n */\nexport function randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\n/**\n * 获取 [min, max) 的随机浮点数\n */\nexport function randomFloat(min: number, max: number): number {\n return Math.random() * (max - min) + min\n}\n\n/**\n * 从数组中随机取若干项,不可重复\n */\nexport function sample<T>(arr: T[], count: number): T[] {\n return shuffle(arr).slice(0, count)\n}\n\n/**\n * 从数组中随机取若干项,可重复\n */\nexport function sampleWithReplacement<T>(arr: T[], count: number): T[] {\n const result: T[] = []\n for (let i = 0; i < count; i++) {\n const index = randomInt(0, arr.length - 1)\n result.push(arr[index])\n }\n return result\n}\n\n/**\n * 从数组中获取随机项\n */\nexport function sampleOne<T>(arr: T[]): T {\n return arr[randomInt(0, arr.length - 1)]\n}\n\n/**\n * 获取 1~n 的随机数\n */\nexport function random1ToN(n: number): number {\n return randomInt(1, n)\n}\n","/**\n * 支持取消的 sleep\n * @param ms 延迟毫秒数\n * @param signal 取消信号\n */\nexport function sleep(ms: number, signal?: AbortSignal) {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) return reject(new Error('取消操作'))\n\n const timer = setTimeout(() => {\n cleanup()\n resolve()\n }, ms)\n\n const onAbort = () => {\n clearTimeout(timer)\n cleanup()\n reject(new Error('取消操作'))\n }\n\n const cleanup = () => {\n signal?.removeEventListener('abort', onAbort)\n }\n\n signal?.addEventListener('abort', onAbort)\n })\n}\n\n/**\n * 支持取消的随机 sleep\n * @param minMS 最小延迟毫秒数\n * @param maxMS 最大延迟毫秒数\n * @param signal 取消信号\n */\nexport function sleepRandom(minMS: number, maxMS: number, signal?: AbortSignal) {\n const ms = Math.random() * (maxMS - minMS) + minMS\n return sleep(ms, signal)\n}\n","import dayjs from 'dayjs'\n\n/**\n * 格式化时间为 2020-02-02 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedDateTime(date?: Date): string {\n return dayjs(date).format('YYYY-MM-DD HH:mm:ss')\n}\n\n/**\n * 格式化时间为 2020-02-02 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedDate(date?: Date): string {\n return dayjs(date).format('YYYY-MM-DD')\n}\n\n/**\n * 格式化时间为 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedTime(date?: Date): string {\n return dayjs(date).format('HH:mm:ss')\n}\n","import type { ParsedUrl } from '../types/utl.js'\n\n/** URL query 中必须编码的保留字符 (RFC 3986) */\nexport const invalidCharRegex = /[!'()*]/g\n\n/** 查询参数 */\nexport type QueryParams = Record<string, string | number | boolean | null | undefined>\n\n/**\n * 判断字符串是否为有效的 HTTP/HTTPS URL\n * @param path - 待检测的字符串\n */\nexport function isHttpUrl(path: string) {\n try {\n const url = new URL(path)\n return url.protocol === 'http:' || url.protocol === 'https:'\n } catch {\n return false\n }\n}\n\n/**\n * 解析 url\n * @param url\n */\nexport function parseUrl(url: string): ParsedUrl {\n try {\n const { origin, pathname, searchParams } = new URL(url)\n return {\n baseUrl: origin + pathname,\n searchParams,\n }\n } catch {\n throw new Error('Invalid URL')\n }\n}\n\n/**\n * 编码 URL 参数\n * @param params 查询参数\n */\nexport function encodeURLParams(params: QueryParams) {\n return (\n Object.keys(params)\n // 排序\n .sort()\n // 编码 key 和 value\n .map((key) => {\n const raw = params[key]\n if (raw === undefined || raw === null) return ''\n\n const value = String(raw).replace(invalidCharRegex, '')\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`\n })\n // 拼接\n .join('&')\n )\n}\n\n/**\n *\n */\n/**\n * 合并查询参数\n * @param urlSearchParams url解析后查询参数\n * @param params 单独传的查询参数\n */\nexport function mergeQueryParams(urlSearchParams: URLSearchParams, params?: QueryParams): QueryParams {\n let mergedParams: QueryParams = {}\n if (urlSearchParams.size > 0) {\n // 合并url里的查询参数\n urlSearchParams.forEach((value, key) => {\n mergedParams[key] = value\n })\n }\n // 处理单独传的查询参数对象\n if (params) {\n mergedParams = { ...mergedParams, ...params }\n }\n return mergedParams\n}\n","/**\n * 生成 CSS `color-mix()` 函数的字符串表示,用于动态计算两种颜色的混合结果\n *\n * @param {string} color1 - 参与混合的第一种颜色(支持 CSS 合法颜色值,如 HEX、RGB、HSL 等)\n * @param {string} color2 - 参与混合的第二种颜色\n * @param {number} percentage - 主颜色(color1)在混合中的占比(百分比数值,范围 0-100)\n * @param {'srgb' | 'hsl'} [colorSpace='srgb'] - 色彩空间选项:\n * - `'srgb'`: 标准 RGB 色彩空间(默认)\n * - `'hsl'`: 色相-饱和度-明度色彩空间\n * @param {number} [percentage2] - 可选参数:副颜色(color2)的独立占比。\n * 若未提供,则自动计算为 `100 - percentage`\n * @returns {string} 可直接用于 CSS 的 `color-mix()` 函数字符串(如 `color-mix(in srgb, red 30%, blue 70%)`)\n *\n * @example\n * // 基础用法(自动计算互补占比)\n * mixColor('red', 'blue', 30)\n * // 返回: \"color-mix(in srgb, red 30%, blue 70%)\"\n *\n * @example\n * // 显式指定双占比 + HSL 色彩空间\n * mixColor('#ff0000', '#0000ff', 40, 'hsl', 60)\n * // 返回: \"color-mix(in hsl, #ff0000 40%, #0000ff 60%)\"\n */\nexport const mixColor = (\n color1: string,\n color2: string,\n percentage: number,\n colorSpace: 'srgb' | 'hsl' = 'srgb',\n percentage2?: number,\n): string => {\n return `color-mix(in ${colorSpace}, ${color1} ${percentage}%, ${color2} ${percentage2 ? percentage2 : 100 - percentage}%)`\n}\n\n/**\n * 将十六进制颜色转换为 RGB\n */\nexport const hexToRgb = (hex: string): { r: number; g: number; b: number } => {\n const r = parseInt(hex.slice(1, 3), 16)\n const g = parseInt(hex.slice(3, 5), 16)\n const b = parseInt(hex.slice(5, 7), 16)\n return { r, g, b }\n}\n","/**\n * 设置 html 根元素的 css 变量\n */\nexport const setCssVar = (k: string, v: string) => {\n document.documentElement.style.setProperty(k, v)\n}\n","/**\n * 等待 <img> 加载完成\n */\nexport function whenImageLoaded(img: HTMLImageElement): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n if (img.dataset['state'] === 'loading') {\n img.src = img.dataset['src']!\n }\n\n if (img.complete && img.naturalWidth > 0) {\n resolve(img)\n return\n }\n\n const onLoad = () => {\n cleanup()\n resolve(img)\n }\n\n const onError = () => {\n cleanup()\n reject(new Error(`图片加载失败: ${img.src}`))\n }\n\n const cleanup = () => {\n img.removeEventListener('load', onLoad)\n img.removeEventListener('error', onError)\n }\n\n img.addEventListener('load', onLoad)\n img.addEventListener('error', onError)\n })\n}\n\n/**\n * 从 <img> 元素获取图片字节数据(ArrayBuffer)\n * @param img 已加载的 <img> 元素\n * @param type 图片类型,可选(默认 png)\n */\nexport async function getImageArrayBuffer(img: HTMLImageElement, type: string = 'image/png'): Promise<ArrayBuffer> {\n const canvas = document.createElement('canvas')\n canvas.width = img.naturalWidth\n canvas.height = img.naturalHeight\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('无法创建 Canvas 2D 上下文')\n ctx.drawImage(img, 0, 0)\n\n const blob: Blob = await new Promise((resolve, reject) => {\n canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('toBlob 失败'))), type)\n })\n\n return await blob.arrayBuffer()\n}\n\n/**\n * 等待加载完成并获取字节数据\n */\nexport async function getImgArrayBufferAfterLoad(img: HTMLImageElement, type?: string): Promise<ArrayBuffer> {\n const loaded = await whenImageLoaded(img)\n return await getImageArrayBuffer(loaded, type)\n}\n","/** 可见性改变的监听器 */\nexport interface VisibilityChangeListener {\n (hidden: boolean): void\n}\n\n/**\n * 监听页面可见性变化(兼容旧的IE/Chrome)\n * @param listener 监听器\n * @returns 成功监听时返回解绑函数\n */\nexport function onVisibilityChange(listener: VisibilityChangeListener) {\n let hiddenPropName: string | undefined = undefined,\n hiddenEventName: string | undefined = undefined\n\n if (typeof document.hidden !== 'undefined') {\n // 现代 Web API\n hiddenPropName = 'hidden'\n hiddenEventName = 'visibilitychange'\n } else if ('msHidden' in document && typeof document.msHidden !== 'undefined') {\n // 旧 IE\n hiddenPropName = 'msHidden'\n hiddenEventName = 'msvisibilitychange'\n } else if ('webkitHidden' in document && typeof document.webkitHidden !== 'undefined') {\n // 旧 Chrome\n hiddenPropName = 'webkitHidden'\n hiddenEventName = 'webkitvisibilitychange'\n }\n\n if (!hiddenPropName || !hiddenEventName) {\n return null\n }\n\n const handler = () => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n listener(document[hiddenPropName])\n }\n\n document.addEventListener(hiddenEventName, handler)\n\n return () => {\n document.removeEventListener(hiddenEventName, handler)\n }\n}\n","/**\n * 滚动元素到屏幕中心\n * @param el\n */\nexport async function humanScrollElIntoCenter(el: HTMLElement) {\n if (!el) return\n\n const rect = el.getBoundingClientRect()\n const doc = document.documentElement\n const body = document.body\n\n const scrollX = window.scrollX || doc.scrollLeft || body.scrollLeft\n const scrollY = window.scrollY || doc.scrollTop || body.scrollTop\n\n const viewW = window.innerWidth\n const viewH = window.innerHeight\n\n // 目标中心点相对页面的位置\n const targetX = rect.left + scrollX + rect.width / 2 - viewW / 2\n const targetY = rect.top + scrollY + rect.height / 2 - viewH / 2\n\n const maxX = Math.max(0, body.scrollWidth - viewW)\n const maxY = Math.max(0, body.scrollHeight - viewH)\n\n // 页面不需要滚动\n if (maxX === 0 && maxY === 0) return\n\n // 水平滚动:仅在可滚动时\n const newX = maxX > 0 ? Math.min(Math.max(targetX, 0), maxX) : scrollX\n // 垂直滚动\n const newY = maxY > 0 ? Math.min(Math.max(targetY, 0), maxY) : scrollY\n\n // 判断是否真正需要滚动\n const needScrollX = Math.abs(window.scrollX - newX) > 1\n const needScrollY = Math.abs(window.scrollY - newY) > 1\n if (!needScrollX && !needScrollY) return\n\n await humanScrollTo(newX, newY)\n}\n\n/**\n * 等待滚动\n */\nexport function waitScrollTo(targetX: number, targetY: number): Promise<void> {\n return new Promise((resolve) => {\n const currentX = window.scrollX\n const currentY = window.scrollY\n\n // 若无需滚动\n if (Math.abs(currentX - targetX) < 1 && Math.abs(currentY - targetY) < 1) {\n resolve()\n return\n }\n\n let timer: number | undefined\n let finished = false\n\n const cleanup = () => {\n if (finished) return\n finished = true\n window.removeEventListener('scroll', handler)\n if (timer) clearTimeout(timer)\n resolve()\n }\n\n const handler = () => {\n if (timer) clearTimeout(timer)\n // 若 50ms 内无新滚动事件,则视为滚动结束\n timer = window.setTimeout(cleanup, 50)\n }\n\n // 启动兜底超时(比如滚动事件根本不触发)\n const failSafe = window.setTimeout(() => {\n console.debug('[waitScrollTo] fallback timeout reached')\n cleanup()\n }, 1000)\n\n const cleanupWithTimeout = () => {\n cleanup()\n clearTimeout(failSafe)\n }\n\n // 替换 cleanup,确保清理超时器\n const finalHandler = () => {\n if (timer) clearTimeout(timer)\n timer = window.setTimeout(cleanupWithTimeout, 50)\n }\n\n // 注册事件\n window.addEventListener('scroll', finalHandler, { passive: true })\n\n // 立即触发滚动\n window.scrollTo({ left: targetX, top: targetY })\n\n // 有时浏览器同步滚动,不触发 scroll 事件\n requestAnimationFrame(() => {\n const nowX = window.scrollX\n const nowY = window.scrollY\n if (Math.abs(nowX - targetX) < 1 && Math.abs(nowY - targetY) < 1) {\n cleanupWithTimeout()\n }\n })\n })\n}\n\n/**\n * 模拟人类手感滚动到指定位置\n */\nexport async function humanScrollTo(targetX: number, targetY: number): Promise<void> {\n return new Promise<void>((resolve) => {\n let currentX = window.scrollX\n let currentY = window.scrollY\n\n async function step() {\n const dx = targetX - currentX\n const dy = targetY - currentY\n\n // 如果距离足够小,直接跳到目标结束\n if (Math.abs(dx) < 1 && Math.abs(dy) < 1) {\n window.scrollTo(targetX, targetY)\n resolve()\n return\n }\n\n // 随机步长 (最小 2px,最大剩余距离的 20%)\n const stepX = Math.sign(dx) * Math.min(Math.max(2, Math.random() * Math.abs(dx) * 0.2), Math.abs(dx))\n const stepY = Math.sign(dy) * Math.min(Math.max(2, Math.random() * Math.abs(dy) * 0.2), Math.abs(dy))\n\n currentX += stepX\n currentY += stepY\n await waitScrollTo(currentX, currentY)\n\n // 随机短暂停顿 10~30ms\n const delay = 10 + Math.random() * 20\n setTimeout(step, delay)\n }\n\n step()\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/utils/error.ts","../src/common/error.ts","../src/common/biz-result.ts","../src/utils/array.ts","../src/utils/function.ts","../src/utils/github.ts","../src/utils/network.ts","../src/utils/random.ts","../src/utils/sleep.ts","../src/utils/time.ts","../src/utils/url.ts","../src/utils/dom/color.ts","../src/utils/dom/css.ts","../src/utils/dom/img.ts","../src/utils/dom/page.ts","../src/utils/dom/scroll.ts"],"sourcesContent":["import { CommonError } from '../common/error.js'\n\n/**\n * 判断是否为通用异常\n */\nexport function isCommonError(error: unknown): error is CommonError {\n return error instanceof CommonError\n}\n\n/**\n * 设置异常信息的前置提示\n * @param error 异常\n * @param preMsg 前置信息 `${preMsg}${error.message}`\n */\nexport function prependErrorMessage(error: CommonError, preMsg?: string): CommonError {\n if (preMsg) {\n error.message = `${preMsg} ${error.message}`\n }\n return error\n}\n\n/**\n * 转换到通用异常\n * @param error 异常\n * @param preMsg 前置提示 `${preMsg}${error.message}`\n */\nexport function convertToCommonError(error: unknown, preMsg?: string): CommonError {\n if (isCommonError(error)) {\n return prependErrorMessage(error, preMsg)\n }\n if (\n typeof error === 'object' &&\n error !== null &&\n 'message' in error &&\n typeof (error as Record<string, unknown>).message === 'string'\n ) {\n const newError = error as { message: string }\n return prependErrorMessage(new CommonError(newError.message), preMsg)\n } else {\n // 如果抛出的异常不是object\n return prependErrorMessage(new CommonError(String(error)), preMsg)\n }\n}\n\n/**\n * 获取异常信息\n */\nexport function getErrorMessage(error: unknown): string {\n return convertToCommonError(error).message\n}\n","import { getErrorMessage } from '../utils/error.js'\n\n/**\n * 通用异常\n */\nexport class CommonError extends Error {\n // 异常信息\n message: string\n // 原始异常\n rawError?: Error\n\n constructor(message: string, rawError?: Error) {\n super(message)\n this.message = rawError ? `${message} ${getErrorMessage(rawError)}` : message\n this.rawError = rawError\n }\n}\n\n/**\n * 中止异常\n */\nexport class AbortError extends CommonError {\n constructor() {\n super('操作已取消')\n }\n}\n","import { CommonError } from './error.js'\nimport { getErrorMessage } from '../utils/error.js'\n\n/**\n * 业务执行结果\n */\nexport class BizResult<T> {\n success: boolean\n msg: string\n data?: T\n\n constructor(success: boolean, msg: string, data?: T) {\n this.success = success\n this.msg = msg\n this.data = data\n }\n\n static createSuccess<T>(data: T) {\n return new BizResult(true, '操作成功', data)\n }\n\n static createFail<T>(msg: string = '操作失败', data?: T) {\n return new BizResult(false, msg, data)\n }\n\n static createError<T>(e: unknown) {\n return new BizResult<T>(false, getErrorMessage(e))\n }\n\n /**\n * 展开成Promise\n */\n async toPromise(): Promise<void>\n async toPromise<T>(): Promise<T>\n async toPromise<T = void>(): Promise<T> {\n if (this.success) {\n return this.data as T\n } else {\n throw new CommonError(this.msg)\n }\n }\n}\n\n/**\n * 执行业务(自动包裹BuResult)\n * @param run 执行方法\n */\nexport const execBiz = async <T>(run: () => Promise<T>): Promise<BizResult<T>> => {\n try {\n return BizResult.createSuccess<T>(await run())\n } catch (e) {\n return BizResult.createError(e)\n }\n}\n","/**\n * 是否为空数组\n * @param data\n */\nexport function isEmptyArr(data: unknown) {\n return Array.isArray(data) && data.length === 0\n}\n\n/**\n * 将数组分块为指定大小的多个子数组\n * @param arr 原数组\n * @param size 每个块的长度\n * @example chunk([1,2,3,4,5], 2) => [[1,2],[3,4],[5]]\n */\nexport function chunk<T>(arr: T[], size: number): T[][] {\n if (!Number.isInteger(size) || size < 1) throw new Error('size 必须是正整数')\n const result: T[][] = []\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size))\n }\n return result\n}\n","/**\n * 随机运行参数\n * @param fns\n * @param maxCount 最多执行次数(1 ~ fns.length)\n */\nexport function runRandomFunctions(fns: Array<() => void>, maxCount?: number): void {\n maxCount = maxCount ?? fns.length\n const count = Math.floor(Math.random() * maxCount) + 1\n\n const shuffled = [...fns]\n for (let i = shuffled.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]\n }\n\n const selected = shuffled.slice(0, count)\n\n for (const fn of selected) {\n fn()\n }\n}\n\n/**\n * 将数字范围按批次处理,每个批次调用一次异步函数\n *\n * @param start - 起始值(包含)\n * @param end - 结束值(包含)\n * @param batchSize - 每批最大元素个数\n * @param processor - 处理单批数字数组的异步函数\n *\n * @example\n * // 分批处理 1..10,每批最多 3 个数字\n * await processRangeInBatches(1, 10, 3, async (batch) => {\n * console.log(batch) // 输出: [1,2,3], [4,5,6], [7,8,9], [10]\n * })\n */\nexport async function processRangeInBatches(\n start: number,\n end: number,\n batchSize: number,\n processor: (batch: number[]) => Promise<void>,\n): Promise<void> {\n for (let current = start; current <= end; current += batchSize) {\n const remaining = end - current + 1\n const actualSize = Math.min(batchSize, remaining)\n const batch = Array.from({ length: actualSize }, (_, idx) => current + idx)\n\n await processor(batch)\n }\n}\n","import { CommonError } from '../common/error.js'\nimport type { GithubRepository } from '../types/github.js'\n\n/**\n * 从 url 解析 github 仓库信息\n * @param repositoryUrl 仓库 URL(支持带有git+前缀、具体文件路径)\n */\nexport function parseGithubRepo(repositoryUrl: string): GithubRepository {\n // 去掉 git+ 前缀\n repositoryUrl = repositoryUrl.replace(/^git\\+/, '')\n\n const regexBase = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+?)(?:\\.git|\\/)?$/\n const regexFile = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)\\/blob\\/([^/]+)$/\n\n // 情况 1:git clone 地址 或 repo 根路径\n const m1 = repositoryUrl.match(regexBase)\n if (m1) {\n return {\n owner: m1[1],\n repo: m1[2],\n branch: 'main', // 默认分支 main\n }\n }\n\n // 情况 2:具体文件路径\n const m2 = repositoryUrl.match(regexFile)\n if (m2) {\n return {\n owner: m2[1],\n repo: m2[2],\n branch: m2[3],\n }\n }\n\n throw new CommonError('解析插件仓库URL失败')\n}\n","import type { NetworkInfo, NetworkState } from '../types/network.js'\n\nfunction isConnection(obj: unknown): obj is NetworkInfo {\n return obj !== null && typeof obj === 'object' && 'downlink' in obj && 'rtt' in obj && 'effectiveType' in obj\n}\n\n/**\n * 获取网络信息\n */\nexport function getNetworkInfo(): NetworkState {\n if (!navigator.onLine) {\n return 'offline'\n }\n\n if ('connection' in navigator && isConnection(navigator.connection)) {\n // 现代 Web API 直接获取网络连接的信息\n const connection = navigator.connection\n return {\n downlink: connection.downlink,\n rtt: connection.rtt,\n effectiveType: connection.effectiveType,\n }\n } else {\n return 'online'\n }\n}\n\n/**\n * 监听网络状态变化\n * @param listener 监听器\n * @returns 成功监听时返回解绑函数\n */\nexport function onNetworkChange(listener: (info: NetworkState) => void) {\n const handleChange = () => {\n listener(getNetworkInfo())\n }\n\n if ('connection' in navigator && isConnection(navigator.connection)) {\n // 现代 Web API\n const connection = navigator.connection\n connection.addEventListener('change', handleChange)\n return () => connection.removeEventListener('change', handleChange)\n } else {\n window.addEventListener('online', handleChange)\n window.addEventListener('offline', handleChange)\n return () => {\n window.removeEventListener('online', handleChange)\n window.removeEventListener('offline', handleChange)\n }\n }\n}\n","/**\n * 数组洗牌\n */\nexport function shuffle<T>(arr: T[]): T[] {\n const clone = arr.slice()\n for (let i = clone.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[clone[i], clone[j]] = [clone[j], clone[i]]\n }\n return clone\n}\n\n/**\n * 获取 [min, max] 的随机整数\n */\nexport function randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\n/**\n * 获取 [min, max) 的随机浮点数\n */\nexport function randomFloat(min: number, max: number): number {\n return Math.random() * (max - min) + min\n}\n\n/**\n * 从数组中随机取若干项,不可重复\n */\nexport function sample<T>(arr: T[], count: number): T[] {\n return shuffle(arr).slice(0, count)\n}\n\n/**\n * 从数组中随机取若干项,可重复\n */\nexport function sampleWithReplacement<T>(arr: T[], count: number): T[] {\n const result: T[] = []\n for (let i = 0; i < count; i++) {\n const index = randomInt(0, arr.length - 1)\n result.push(arr[index])\n }\n return result\n}\n\n/**\n * 从数组中获取随机项\n */\nexport function sampleOne<T>(arr: T[]): T {\n return arr[randomInt(0, arr.length - 1)]\n}\n\n/**\n * 获取 1~n 的随机数\n */\nexport function random1ToN(n: number): number {\n return randomInt(1, n)\n}\n","/**\n * 支持取消的 sleep\n * @param ms 延迟毫秒数\n * @param signal 取消信号\n */\nexport function sleep(ms: number, signal?: AbortSignal) {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) return reject(new Error('取消操作'))\n\n const timer = setTimeout(() => {\n cleanup()\n resolve()\n }, ms)\n\n const onAbort = () => {\n clearTimeout(timer)\n cleanup()\n reject(new Error('取消操作'))\n }\n\n const cleanup = () => {\n signal?.removeEventListener('abort', onAbort)\n }\n\n signal?.addEventListener('abort', onAbort)\n })\n}\n\n/**\n * 支持取消的随机 sleep\n * @param minMS 最小延迟毫秒数\n * @param maxMS 最大延迟毫秒数\n * @param signal 取消信号\n */\nexport function sleepRandom(minMS: number, maxMS: number, signal?: AbortSignal) {\n const ms = Math.random() * (maxMS - minMS) + minMS\n return sleep(ms, signal)\n}\n","import dayjs from 'dayjs'\n\n/**\n * 格式化时间为 2020-02-02 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedDateTime(date?: Date): string {\n return dayjs(date).format('YYYY-MM-DD HH:mm:ss')\n}\n\n/**\n * 格式化时间为 2020-02-02 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedDate(date?: Date): string {\n return dayjs(date).format('YYYY-MM-DD')\n}\n\n/**\n * 格式化时间为 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedTime(date?: Date): string {\n return dayjs(date).format('HH:mm:ss')\n}\n","import type { ParsedUrl } from '../types/utl.js'\n\n/** URL query 中必须编码的保留字符 (RFC 3986) */\nexport const invalidCharRegex = /[!'()*]/g\n\n/** 查询参数 */\nexport type QueryParams = Record<string, string | number | boolean | null | undefined>\n\n/**\n * 判断字符串是否为有效的 HTTP/HTTPS URL\n * @param path - 待检测的字符串\n */\nexport function isHttpUrl(path: string) {\n try {\n const url = new URL(path)\n return url.protocol === 'http:' || url.protocol === 'https:'\n } catch {\n return false\n }\n}\n\n/**\n * 解析 url\n * @param url\n */\nexport function parseUrl(url: string): ParsedUrl {\n try {\n const { origin, pathname, searchParams } = new URL(url)\n return {\n baseUrl: origin + pathname,\n searchParams,\n }\n } catch {\n throw new Error('Invalid URL')\n }\n}\n\n/**\n * 编码 URL 参数\n * @param params 查询参数\n */\nexport function encodeURLParams(params: QueryParams) {\n return (\n Object.keys(params)\n // 排序\n .sort()\n // 编码 key 和 value\n .map((key) => {\n const raw = params[key]\n if (raw === undefined || raw === null) return ''\n\n const value = String(raw).replace(invalidCharRegex, '')\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`\n })\n // 拼接\n .join('&')\n )\n}\n\n/**\n *\n */\n/**\n * 合并查询参数\n * @param urlSearchParams url解析后查询参数\n * @param params 单独传的查询参数\n */\nexport function mergeQueryParams(urlSearchParams: URLSearchParams, params?: QueryParams): QueryParams {\n let mergedParams: QueryParams = {}\n if (urlSearchParams.size > 0) {\n // 合并url里的查询参数\n urlSearchParams.forEach((value, key) => {\n mergedParams[key] = value\n })\n }\n // 处理单独传的查询参数对象\n if (params) {\n mergedParams = { ...mergedParams, ...params }\n }\n return mergedParams\n}\n","/**\n * 生成 CSS `color-mix()` 函数的字符串表示,用于动态计算两种颜色的混合结果\n *\n * @param {string} color1 - 参与混合的第一种颜色(支持 CSS 合法颜色值,如 HEX、RGB、HSL 等)\n * @param {string} color2 - 参与混合的第二种颜色\n * @param {number} percentage - 主颜色(color1)在混合中的占比(百分比数值,范围 0-100)\n * @param {'srgb' | 'hsl'} [colorSpace='srgb'] - 色彩空间选项:\n * - `'srgb'`: 标准 RGB 色彩空间(默认)\n * - `'hsl'`: 色相-饱和度-明度色彩空间\n * @param {number} [percentage2] - 可选参数:副颜色(color2)的独立占比。\n * 若未提供,则自动计算为 `100 - percentage`\n * @returns {string} 可直接用于 CSS 的 `color-mix()` 函数字符串(如 `color-mix(in srgb, red 30%, blue 70%)`)\n *\n * @example\n * // 基础用法(自动计算互补占比)\n * mixColor('red', 'blue', 30)\n * // 返回: \"color-mix(in srgb, red 30%, blue 70%)\"\n *\n * @example\n * // 显式指定双占比 + HSL 色彩空间\n * mixColor('#ff0000', '#0000ff', 40, 'hsl', 60)\n * // 返回: \"color-mix(in hsl, #ff0000 40%, #0000ff 60%)\"\n */\nexport const mixColor = (\n color1: string,\n color2: string,\n percentage: number,\n colorSpace: 'srgb' | 'hsl' = 'srgb',\n percentage2?: number,\n): string => {\n return `color-mix(in ${colorSpace}, ${color1} ${percentage}%, ${color2} ${percentage2 ? percentage2 : 100 - percentage}%)`\n}\n\n/**\n * 将十六进制颜色转换为 RGB\n */\nexport const hexToRgb = (hex: string): { r: number; g: number; b: number } => {\n const r = parseInt(hex.slice(1, 3), 16)\n const g = parseInt(hex.slice(3, 5), 16)\n const b = parseInt(hex.slice(5, 7), 16)\n return { r, g, b }\n}\n","/**\n * 设置 html 根元素的 css 变量\n */\nexport const setCssVar = (k: string, v: string) => {\n document.documentElement.style.setProperty(k, v)\n}\n","/**\n * 等待 <img> 加载完成\n */\nexport function whenImageLoaded(img: HTMLImageElement): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n if (img.dataset['state'] === 'loading') {\n img.src = img.dataset['src']!\n }\n\n if (img.complete && img.naturalWidth > 0) {\n resolve(img)\n return\n }\n\n const onLoad = () => {\n cleanup()\n resolve(img)\n }\n\n const onError = () => {\n cleanup()\n reject(new Error(`图片加载失败: ${img.src}`))\n }\n\n const cleanup = () => {\n img.removeEventListener('load', onLoad)\n img.removeEventListener('error', onError)\n }\n\n img.addEventListener('load', onLoad)\n img.addEventListener('error', onError)\n })\n}\n\n/**\n * 从 <img> 元素获取图片字节数据(ArrayBuffer)\n * @param img 已加载的 <img> 元素\n * @param type 图片类型,可选(默认 png)\n */\nexport async function getImageArrayBuffer(img: HTMLImageElement, type: string = 'image/png'): Promise<ArrayBuffer> {\n const canvas = document.createElement('canvas')\n canvas.width = img.naturalWidth\n canvas.height = img.naturalHeight\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('无法创建 Canvas 2D 上下文')\n ctx.drawImage(img, 0, 0)\n\n const blob: Blob = await new Promise((resolve, reject) => {\n canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('toBlob 失败'))), type)\n })\n\n return await blob.arrayBuffer()\n}\n\n/**\n * 等待加载完成并获取字节数据\n */\nexport async function getImgArrayBufferAfterLoad(img: HTMLImageElement, type?: string): Promise<ArrayBuffer> {\n const loaded = await whenImageLoaded(img)\n return await getImageArrayBuffer(loaded, type)\n}\n","/** 可见性改变的监听器 */\nexport interface VisibilityChangeListener {\n (hidden: boolean): void\n}\n\n/**\n * 监听页面可见性变化(兼容旧的IE/Chrome)\n * @param listener 监听器\n * @returns 成功监听时返回解绑函数\n */\nexport function onVisibilityChange(listener: VisibilityChangeListener) {\n let hiddenPropName: string | undefined = undefined,\n hiddenEventName: string | undefined = undefined\n\n if (typeof document.hidden !== 'undefined') {\n // 现代 Web API\n hiddenPropName = 'hidden'\n hiddenEventName = 'visibilitychange'\n } else if ('msHidden' in document && typeof document.msHidden !== 'undefined') {\n // 旧 IE\n hiddenPropName = 'msHidden'\n hiddenEventName = 'msvisibilitychange'\n } else if ('webkitHidden' in document && typeof document.webkitHidden !== 'undefined') {\n // 旧 Chrome\n hiddenPropName = 'webkitHidden'\n hiddenEventName = 'webkitvisibilitychange'\n }\n\n if (!hiddenPropName || !hiddenEventName) {\n return null\n }\n\n const handler = () => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n listener(document[hiddenPropName])\n }\n\n document.addEventListener(hiddenEventName, handler)\n\n return () => {\n document.removeEventListener(hiddenEventName, handler)\n }\n}\n","/**\n * 滚动元素到屏幕中心\n * @param el\n */\nexport async function humanScrollElIntoCenter(el: HTMLElement) {\n if (!el) return\n\n const rect = el.getBoundingClientRect()\n const doc = document.documentElement\n const body = document.body\n\n const scrollX = window.scrollX || doc.scrollLeft || body.scrollLeft\n const scrollY = window.scrollY || doc.scrollTop || body.scrollTop\n\n const viewW = window.innerWidth\n const viewH = window.innerHeight\n\n // 目标中心点相对页面的位置\n const targetX = rect.left + scrollX + rect.width / 2 - viewW / 2\n const targetY = rect.top + scrollY + rect.height / 2 - viewH / 2\n\n const maxX = Math.max(0, body.scrollWidth - viewW)\n const maxY = Math.max(0, body.scrollHeight - viewH)\n\n // 页面不需要滚动\n if (maxX === 0 && maxY === 0) return\n\n // 水平滚动:仅在可滚动时\n const newX = maxX > 0 ? Math.min(Math.max(targetX, 0), maxX) : scrollX\n // 垂直滚动\n const newY = maxY > 0 ? Math.min(Math.max(targetY, 0), maxY) : scrollY\n\n // 判断是否真正需要滚动\n const needScrollX = Math.abs(window.scrollX - newX) > 1\n const needScrollY = Math.abs(window.scrollY - newY) > 1\n if (!needScrollX && !needScrollY) return\n\n await humanScrollTo(newX, newY)\n}\n\n/**\n * 等待滚动\n */\nexport function waitScrollTo(targetX: number, targetY: number): Promise<void> {\n return new Promise((resolve) => {\n const currentX = window.scrollX\n const currentY = window.scrollY\n\n // 若无需滚动\n if (Math.abs(currentX - targetX) < 1 && Math.abs(currentY - targetY) < 1) {\n resolve()\n return\n }\n\n let timer: number | undefined\n let finished = false\n\n const cleanup = () => {\n if (finished) return\n finished = true\n window.removeEventListener('scroll', handler)\n if (timer) clearTimeout(timer)\n resolve()\n }\n\n const handler = () => {\n if (timer) clearTimeout(timer)\n // 若 50ms 内无新滚动事件,则视为滚动结束\n timer = window.setTimeout(cleanup, 50)\n }\n\n // 启动兜底超时(比如滚动事件根本不触发)\n const failSafe = window.setTimeout(() => {\n console.debug('[waitScrollTo] fallback timeout reached')\n cleanup()\n }, 1000)\n\n const cleanupWithTimeout = () => {\n cleanup()\n clearTimeout(failSafe)\n }\n\n // 替换 cleanup,确保清理超时器\n const finalHandler = () => {\n if (timer) clearTimeout(timer)\n timer = window.setTimeout(cleanupWithTimeout, 50)\n }\n\n // 注册事件\n window.addEventListener('scroll', finalHandler, { passive: true })\n\n // 立即触发滚动\n window.scrollTo({ left: targetX, top: targetY })\n\n // 有时浏览器同步滚动,不触发 scroll 事件\n requestAnimationFrame(() => {\n const nowX = window.scrollX\n const nowY = window.scrollY\n if (Math.abs(nowX - targetX) < 1 && Math.abs(nowY - targetY) < 1) {\n cleanupWithTimeout()\n }\n })\n })\n}\n\n/**\n * 模拟人类手感滚动到指定位置\n */\nexport async function humanScrollTo(targetX: number, targetY: number): Promise<void> {\n return new Promise<void>((resolve) => {\n let currentX = window.scrollX\n let currentY = window.scrollY\n\n async function step() {\n const dx = targetX - currentX\n const dy = targetY - currentY\n\n // 如果距离足够小,直接跳到目标结束\n if (Math.abs(dx) < 1 && Math.abs(dy) < 1) {\n window.scrollTo(targetX, targetY)\n resolve()\n return\n }\n\n // 随机步长 (最小 2px,最大剩余距离的 20%)\n const stepX = Math.sign(dx) * Math.min(Math.max(2, Math.random() * Math.abs(dx) * 0.2), Math.abs(dx))\n const stepY = Math.sign(dy) * Math.min(Math.max(2, Math.random() * Math.abs(dy) * 0.2), Math.abs(dy))\n\n currentX += stepX\n currentY += stepY\n await waitScrollTo(currentX, currentY)\n\n // 随机短暂停顿 10~30ms\n const delay = 10 + Math.random() * 20\n setTimeout(step, delay)\n }\n\n step()\n })\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`nanoid`),l=require(`dayjs`);l=s(l,1);function u(e){return e instanceof m}function d(e,t){return t&&(e.message=`${t} ${e.message}`),e}function f(e,t){return u(e)?d(e,t):typeof e==`object`&&e&&`message`in e&&typeof e.message==`string`?d(new m(e.message),t):d(new m(String(e)),t)}function p(e){return f(e).message}var m=class extends Error{message;rawError;constructor(e,t){super(e),this.message=t?`${e} ${p(t)}`:e,this.rawError=t}},h=class extends m{constructor(){super(`操作已取消`)}},g=class e{success;msg;data;constructor(e,t,n){this.success=e,this.msg=t,this.data=n}static createSuccess(t){return new e(!0,`操作成功`,t)}static createFail(t=`操作失败`,n){return new e(!1,t,n)}static createError(t){return new e(!1,p(t))}async toPromise(){if(this.success)return this.data;throw new m(this.msg)}},_=async e=>{try{return g.createSuccess(await e())}catch(e){return g.createError(e)}};function v(e){return Array.isArray(e)&&e.length===0}function y(e,t){if(!Number.isInteger(t)||t<1)throw Error(`size 必须是正整数`);let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}function b(e,t){t??=e.length;let n=Math.floor(Math.random()*t)+1,r=[...e];for(let e=r.length-1;e>0;e--){let t=Math.floor(Math.random()*(e+1));[r[e],r[t]]=[r[t],r[e]]}let i=r.slice(0,n);for(let e of i)e()}async function x(e,t,n,r){for(let i=e;i<=t;i+=n){let e=t-i+1,a=Math.min(n,e);await r(Array.from({length:a},(e,t)=>i+t))}}function S(e){e=e.replace(/^git\+/,``);let t=/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git|\/)?$/,n=/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)$/,r=e.match(t);if(r)return{owner:r[1],repo:r[2],branch:`main`};let i=e.match(n);if(i)return{owner:i[1],repo:i[2],branch:i[3]};throw new m(`解析插件仓库URL失败`)}function C(){return(0,c.nanoid)()}function w(e){return typeof e==`object`&&!!e&&`downlink`in e&&`rtt`in e&&`effectiveType`in e}function T(){if(!navigator.onLine)return`offline`;if(`connection`in navigator&&w(navigator.connection)){let e=navigator.connection;return{downlink:e.downlink,rtt:e.rtt,effectiveType:e.effectiveType}}else return`online`}function E(e){let t=()=>{e(T())};if(`connection`in navigator&&w(navigator.connection)){let e=navigator.connection;return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)}else return window.addEventListener(`online`,t),window.addEventListener(`offline`,t),()=>{window.removeEventListener(`online`,t),window.removeEventListener(`offline`,t)}}function D(e){let t=e.slice();for(let e=t.length-1;e>0;e--){let n=Math.floor(Math.random()*(e+1));[t[e],t[n]]=[t[n],t[e]]}return t}function O(e,t){return Math.floor(Math.random()*(t-e+1))+e}function k(e,t){return Math.random()*(t-e)+e}function A(e,t){return D(e).slice(0,t)}function j(e,t){let n=[];for(let r=0;r<t;r++){let t=O(0,e.length-1);n.push(e[t])}return n}function M(e){return e[O(0,e.length-1)]}function N(e){return O(1,e)}function P(e,t){return new Promise((n,r)=>{if(t?.aborted)return r(Error(`取消操作`));let i=setTimeout(()=>{o(),n()},e),a=()=>{clearTimeout(i),o(),r(Error(`取消操作`))},o=()=>{t?.removeEventListener(`abort`,a)};t?.addEventListener(`abort`,a)})}function F(e,t,n){return P(Math.random()*(t-e)+e,n)}function I(e){return(0,l.default)(e).format(`YYYY-MM-DD HH:mm:ss`)}function L(e){return(0,l.default)(e).format(`YYYY-MM-DD`)}function R(e){return(0,l.default)(e).format(`HH:mm:ss`)}var z=/[!'()*]/g;function B(e){try{let t=new URL(e);return t.protocol===`http:`||t.protocol===`https:`}catch{return!1}}function V(e){try{let{origin:t,pathname:n,searchParams:r}=new URL(e);return{baseUrl:t+n,searchParams:r}}catch{throw Error(`Invalid URL`)}}function H(e){return Object.keys(e).sort().map(t=>{let n=e[t];if(n==null)return``;let r=String(n).replace(z,``);return`${encodeURIComponent(t)}=${encodeURIComponent(r)}`}).join(`&`)}function U(e,t){let n={};return e.size>0&&e.forEach((e,t)=>{n[t]=e}),t&&(n={...n,...t}),n}var W=(e,t,n,r=`srgb`,i)=>`color-mix(in ${r}, ${e} ${n}%, ${t} ${i||100-n}%)`,G=e=>({r:parseInt(e.slice(1,3),16),g:parseInt(e.slice(3,5),16),b:parseInt(e.slice(5,7),16)}),K=(e,t)=>{document.documentElement.style.setProperty(e,t)};function q(e){return new Promise((t,n)=>{if(e.dataset.state===`loading`&&(e.src=e.dataset.src),e.complete&&e.naturalWidth>0){t(e);return}let r=()=>{a(),t(e)},i=()=>{a(),n(Error(`图片加载失败: ${e.src}`))},a=()=>{e.removeEventListener(`load`,r),e.removeEventListener(`error`,i)};e.addEventListener(`load`,r),e.addEventListener(`error`,i)})}async function J(e,t=`image/png`){let n=document.createElement(`canvas`);n.width=e.naturalWidth,n.height=e.naturalHeight;let r=n.getContext(`2d`);if(!r)throw Error(`无法创建 Canvas 2D 上下文`);return r.drawImage(e,0,0),await(await new Promise((e,r)=>{n.toBlob(t=>t?e(t):r(Error(`toBlob 失败`)),t)})).arrayBuffer()}async function Y(e,t){return await J(await q(e),t)}function X(e){let t,n;if(document.hidden===void 0?`msHidden`in document&&document.msHidden!==void 0?(t=`msHidden`,n=`msvisibilitychange`):`webkitHidden`in document&&document.webkitHidden!==void 0&&(t=`webkitHidden`,n=`webkitvisibilitychange`):(t=`hidden`,n=`visibilitychange`),!t||!n)return null;let r=()=>{e(document[t])};return document.addEventListener(n,r),()=>{document.removeEventListener(n,r)}}async function Z(e){if(!e)return;let t=e.getBoundingClientRect(),n=document.documentElement,r=document.body,i=window.scrollX||n.scrollLeft||r.scrollLeft,a=window.scrollY||n.scrollTop||r.scrollTop,o=window.innerWidth,s=window.innerHeight,c=t.left+i+t.width/2-o/2,l=t.top+a+t.height/2-s/2,u=Math.max(0,r.scrollWidth-o),d=Math.max(0,r.scrollHeight-s);if(u===0&&d===0)return;let f=u>0?Math.min(Math.max(c,0),u):i,p=d>0?Math.min(Math.max(l,0),d):a,m=Math.abs(window.scrollX-f)>1,h=Math.abs(window.scrollY-p)>1;!m&&!h||await $(f,p)}function Q(e,t){return new Promise(n=>{let r=window.scrollX,i=window.scrollY;if(Math.abs(r-e)<1&&Math.abs(i-t)<1){n();return}let a,o=!1,s=()=>{o||(o=!0,window.removeEventListener(`scroll`,c),a&&clearTimeout(a),n())},c=()=>{a&&clearTimeout(a),a=window.setTimeout(s,50)},l=window.setTimeout(()=>{console.debug(`[waitScrollTo] fallback timeout reached`),s()},1e3),u=()=>{s(),clearTimeout(l)};window.addEventListener(`scroll`,()=>{a&&clearTimeout(a),a=window.setTimeout(u,50)},{passive:!0}),window.scrollTo({left:e,top:t}),requestAnimationFrame(()=>{let n=window.scrollX,r=window.scrollY;Math.abs(n-e)<1&&Math.abs(r-t)<1&&u()})})}async function $(e,t){return new Promise(n=>{let r=window.scrollX,i=window.scrollY;async function a(){let o=e-r,s=t-i;if(Math.abs(o)<1&&Math.abs(s)<1){window.scrollTo(e,t),n();return}let c=Math.sign(o)*Math.min(Math.max(2,Math.random()*Math.abs(o)*.2),Math.abs(o)),l=Math.sign(s)*Math.min(Math.max(2,Math.random()*Math.abs(s)*.2),Math.abs(s));r+=c,i+=l,await Q(r,i);let u=10+Math.random()*20;setTimeout(a,u)}a()})}exports.AbortError=h,exports.BizResult=g,exports.CommonError=m,exports.chunk=y,exports.convertToCommonError=f,exports.encodeURLParams=H,exports.execBiz=_,exports.generateId=C,exports.getErrorMessage=p,exports.getFormattedDate=L,exports.getFormattedDateTime=I,exports.getFormattedTime=R,exports.getImageArrayBuffer=J,exports.getImgArrayBufferAfterLoad=Y,exports.getNetworkInfo=T,exports.hexToRgb=G,exports.humanScrollElIntoCenter=Z,exports.humanScrollTo=$,exports.invalidCharRegex=z,exports.isCommonError=u,exports.isEmptyArr=v,exports.isHttpUrl=B,exports.mergeQueryParams=U,exports.mixColor=W,exports.onNetworkChange=E,exports.onVisibilityChange=X,exports.parseGithubRepo=S,exports.parseUrl=V,exports.prependErrorMessage=d,exports.processRangeInBatches=x,exports.random1ToN=N,exports.randomFloat=k,exports.randomInt=O,exports.runRandomFunctions=b,exports.sample=A,exports.sampleOne=M,exports.sampleWithReplacement=j,exports.setCssVar=K,exports.shuffle=D,exports.sleep=P,exports.sleepRandom=F,exports.waitScrollTo=Q,exports.whenImageLoaded=q;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`dayjs`);c=s(c,1);function l(e){return e instanceof p}function u(e,t){return t&&(e.message=`${t} ${e.message}`),e}function d(e,t){return l(e)?u(e,t):typeof e==`object`&&e&&`message`in e&&typeof e.message==`string`?u(new p(e.message),t):u(new p(String(e)),t)}function f(e){return d(e).message}var p=class extends Error{message;rawError;constructor(e,t){super(e),this.message=t?`${e} ${f(t)}`:e,this.rawError=t}},m=class extends p{constructor(){super(`操作已取消`)}},h=class e{success;msg;data;constructor(e,t,n){this.success=e,this.msg=t,this.data=n}static createSuccess(t){return new e(!0,`操作成功`,t)}static createFail(t=`操作失败`,n){return new e(!1,t,n)}static createError(t){return new e(!1,f(t))}async toPromise(){if(this.success)return this.data;throw new p(this.msg)}},g=async e=>{try{return h.createSuccess(await e())}catch(e){return h.createError(e)}};function _(e){return Array.isArray(e)&&e.length===0}function v(e,t){if(!Number.isInteger(t)||t<1)throw Error(`size 必须是正整数`);let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}function y(e,t){t??=e.length;let n=Math.floor(Math.random()*t)+1,r=[...e];for(let e=r.length-1;e>0;e--){let t=Math.floor(Math.random()*(e+1));[r[e],r[t]]=[r[t],r[e]]}let i=r.slice(0,n);for(let e of i)e()}async function b(e,t,n,r){for(let i=e;i<=t;i+=n){let e=t-i+1,a=Math.min(n,e);await r(Array.from({length:a},(e,t)=>i+t))}}function x(e){e=e.replace(/^git\+/,``);let t=/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git|\/)?$/,n=/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)$/,r=e.match(t);if(r)return{owner:r[1],repo:r[2],branch:`main`};let i=e.match(n);if(i)return{owner:i[1],repo:i[2],branch:i[3]};throw new p(`解析插件仓库URL失败`)}function S(e){return typeof e==`object`&&!!e&&`downlink`in e&&`rtt`in e&&`effectiveType`in e}function C(){if(!navigator.onLine)return`offline`;if(`connection`in navigator&&S(navigator.connection)){let e=navigator.connection;return{downlink:e.downlink,rtt:e.rtt,effectiveType:e.effectiveType}}else return`online`}function w(e){let t=()=>{e(C())};if(`connection`in navigator&&S(navigator.connection)){let e=navigator.connection;return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)}else return window.addEventListener(`online`,t),window.addEventListener(`offline`,t),()=>{window.removeEventListener(`online`,t),window.removeEventListener(`offline`,t)}}function T(e){let t=e.slice();for(let e=t.length-1;e>0;e--){let n=Math.floor(Math.random()*(e+1));[t[e],t[n]]=[t[n],t[e]]}return t}function E(e,t){return Math.floor(Math.random()*(t-e+1))+e}function D(e,t){return Math.random()*(t-e)+e}function O(e,t){return T(e).slice(0,t)}function k(e,t){let n=[];for(let r=0;r<t;r++){let t=E(0,e.length-1);n.push(e[t])}return n}function A(e){return e[E(0,e.length-1)]}function j(e){return E(1,e)}function M(e,t){return new Promise((n,r)=>{if(t?.aborted)return r(Error(`取消操作`));let i=setTimeout(()=>{o(),n()},e),a=()=>{clearTimeout(i),o(),r(Error(`取消操作`))},o=()=>{t?.removeEventListener(`abort`,a)};t?.addEventListener(`abort`,a)})}function N(e,t,n){return M(Math.random()*(t-e)+e,n)}function P(e){return(0,c.default)(e).format(`YYYY-MM-DD HH:mm:ss`)}function F(e){return(0,c.default)(e).format(`YYYY-MM-DD`)}function I(e){return(0,c.default)(e).format(`HH:mm:ss`)}var L=/[!'()*]/g;function R(e){try{let t=new URL(e);return t.protocol===`http:`||t.protocol===`https:`}catch{return!1}}function z(e){try{let{origin:t,pathname:n,searchParams:r}=new URL(e);return{baseUrl:t+n,searchParams:r}}catch{throw Error(`Invalid URL`)}}function B(e){return Object.keys(e).sort().map(t=>{let n=e[t];if(n==null)return``;let r=String(n).replace(L,``);return`${encodeURIComponent(t)}=${encodeURIComponent(r)}`}).join(`&`)}function V(e,t){let n={};return e.size>0&&e.forEach((e,t)=>{n[t]=e}),t&&(n={...n,...t}),n}var H=(e,t,n,r=`srgb`,i)=>`color-mix(in ${r}, ${e} ${n}%, ${t} ${i||100-n}%)`,U=e=>({r:parseInt(e.slice(1,3),16),g:parseInt(e.slice(3,5),16),b:parseInt(e.slice(5,7),16)}),W=(e,t)=>{document.documentElement.style.setProperty(e,t)};function G(e){return new Promise((t,n)=>{if(e.dataset.state===`loading`&&(e.src=e.dataset.src),e.complete&&e.naturalWidth>0){t(e);return}let r=()=>{a(),t(e)},i=()=>{a(),n(Error(`图片加载失败: ${e.src}`))},a=()=>{e.removeEventListener(`load`,r),e.removeEventListener(`error`,i)};e.addEventListener(`load`,r),e.addEventListener(`error`,i)})}async function K(e,t=`image/png`){let n=document.createElement(`canvas`);n.width=e.naturalWidth,n.height=e.naturalHeight;let r=n.getContext(`2d`);if(!r)throw Error(`无法创建 Canvas 2D 上下文`);return r.drawImage(e,0,0),await(await new Promise((e,r)=>{n.toBlob(t=>t?e(t):r(Error(`toBlob 失败`)),t)})).arrayBuffer()}async function q(e,t){return await K(await G(e),t)}function J(e){let t,n;if(document.hidden===void 0?`msHidden`in document&&document.msHidden!==void 0?(t=`msHidden`,n=`msvisibilitychange`):`webkitHidden`in document&&document.webkitHidden!==void 0&&(t=`webkitHidden`,n=`webkitvisibilitychange`):(t=`hidden`,n=`visibilitychange`),!t||!n)return null;let r=()=>{e(document[t])};return document.addEventListener(n,r),()=>{document.removeEventListener(n,r)}}async function Y(e){if(!e)return;let t=e.getBoundingClientRect(),n=document.documentElement,r=document.body,i=window.scrollX||n.scrollLeft||r.scrollLeft,a=window.scrollY||n.scrollTop||r.scrollTop,o=window.innerWidth,s=window.innerHeight,c=t.left+i+t.width/2-o/2,l=t.top+a+t.height/2-s/2,u=Math.max(0,r.scrollWidth-o),d=Math.max(0,r.scrollHeight-s);if(u===0&&d===0)return;let f=u>0?Math.min(Math.max(c,0),u):i,p=d>0?Math.min(Math.max(l,0),d):a,m=Math.abs(window.scrollX-f)>1,h=Math.abs(window.scrollY-p)>1;!m&&!h||await Z(f,p)}function X(e,t){return new Promise(n=>{let r=window.scrollX,i=window.scrollY;if(Math.abs(r-e)<1&&Math.abs(i-t)<1){n();return}let a,o=!1,s=()=>{o||(o=!0,window.removeEventListener(`scroll`,c),a&&clearTimeout(a),n())},c=()=>{a&&clearTimeout(a),a=window.setTimeout(s,50)},l=window.setTimeout(()=>{console.debug(`[waitScrollTo] fallback timeout reached`),s()},1e3),u=()=>{s(),clearTimeout(l)};window.addEventListener(`scroll`,()=>{a&&clearTimeout(a),a=window.setTimeout(u,50)},{passive:!0}),window.scrollTo({left:e,top:t}),requestAnimationFrame(()=>{let n=window.scrollX,r=window.scrollY;Math.abs(n-e)<1&&Math.abs(r-t)<1&&u()})})}async function Z(e,t){return new Promise(n=>{let r=window.scrollX,i=window.scrollY;async function a(){let o=e-r,s=t-i;if(Math.abs(o)<1&&Math.abs(s)<1){window.scrollTo(e,t),n();return}let c=Math.sign(o)*Math.min(Math.max(2,Math.random()*Math.abs(o)*.2),Math.abs(o)),l=Math.sign(s)*Math.min(Math.max(2,Math.random()*Math.abs(s)*.2),Math.abs(s));r+=c,i+=l,await X(r,i);let u=10+Math.random()*20;setTimeout(a,u)}a()})}exports.AbortError=m,exports.BizResult=h,exports.CommonError=p,exports.chunk=v,exports.convertToCommonError=d,exports.encodeURLParams=B,exports.execBiz=g,exports.getErrorMessage=f,exports.getFormattedDate=F,exports.getFormattedDateTime=P,exports.getFormattedTime=I,exports.getImageArrayBuffer=K,exports.getImgArrayBufferAfterLoad=q,exports.getNetworkInfo=C,exports.hexToRgb=U,exports.humanScrollElIntoCenter=Y,exports.humanScrollTo=Z,exports.invalidCharRegex=L,exports.isCommonError=l,exports.isEmptyArr=_,exports.isHttpUrl=R,exports.mergeQueryParams=V,exports.mixColor=H,exports.onNetworkChange=w,exports.onVisibilityChange=J,exports.parseGithubRepo=x,exports.parseUrl=z,exports.prependErrorMessage=u,exports.processRangeInBatches=b,exports.random1ToN=j,exports.randomFloat=D,exports.randomInt=E,exports.runRandomFunctions=y,exports.sample=O,exports.sampleOne=A,exports.sampleWithReplacement=k,exports.setCssVar=W,exports.shuffle=T,exports.sleep=M,exports.sleepRandom=N,exports.waitScrollTo=X,exports.whenImageLoaded=G;
2
2
  //# sourceMappingURL=index.umd.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.cjs","names":[],"sources":["../src/utils/error.ts","../src/common/error.ts","../src/common/biz-result.ts","../src/utils/array.ts","../src/utils/function.ts","../src/utils/github.ts","../src/utils/id.ts","../src/utils/network.ts","../src/utils/random.ts","../src/utils/sleep.ts","../src/utils/time.ts","../src/utils/url.ts","../src/utils/dom/color.ts","../src/utils/dom/css.ts","../src/utils/dom/img.ts","../src/utils/dom/page.ts","../src/utils/dom/scroll.ts"],"sourcesContent":["import { CommonError } from '../common/error.js'\n\n/**\n * 判断是否为通用异常\n */\nexport function isCommonError(error: unknown): error is CommonError {\n return error instanceof CommonError\n}\n\n/**\n * 设置异常信息的前置提示\n * @param error 异常\n * @param preMsg 前置信息 `${preMsg}${error.message}`\n */\nexport function prependErrorMessage(error: CommonError, preMsg?: string): CommonError {\n if (preMsg) {\n error.message = `${preMsg} ${error.message}`\n }\n return error\n}\n\n/**\n * 转换到通用异常\n * @param error 异常\n * @param preMsg 前置提示 `${preMsg}${error.message}`\n */\nexport function convertToCommonError(error: unknown, preMsg?: string): CommonError {\n if (isCommonError(error)) {\n return prependErrorMessage(error, preMsg)\n }\n if (\n typeof error === 'object' &&\n error !== null &&\n 'message' in error &&\n typeof (error as Record<string, unknown>).message === 'string'\n ) {\n const newError = error as { message: string }\n return prependErrorMessage(new CommonError(newError.message), preMsg)\n } else {\n // 如果抛出的异常不是object\n return prependErrorMessage(new CommonError(String(error)), preMsg)\n }\n}\n\n/**\n * 获取异常信息\n */\nexport function getErrorMessage(error: unknown): string {\n return convertToCommonError(error).message\n}\n","import { getErrorMessage } from '../utils/error.js'\n\n/**\n * 通用异常\n */\nexport class CommonError extends Error {\n // 异常信息\n message: string\n // 原始异常\n rawError?: Error\n\n constructor(message: string, rawError?: Error) {\n super(message)\n this.message = rawError ? `${message} ${getErrorMessage(rawError)}` : message\n this.rawError = rawError\n }\n}\n\n/**\n * 中止异常\n */\nexport class AbortError extends CommonError {\n constructor() {\n super('操作已取消')\n }\n}\n","import { CommonError } from './error.js'\nimport { getErrorMessage } from '../utils/error.js'\n\n/**\n * 业务执行结果\n */\nexport class BizResult<T> {\n success: boolean\n msg: string\n data?: T\n\n constructor(success: boolean, msg: string, data?: T) {\n this.success = success\n this.msg = msg\n this.data = data\n }\n\n static createSuccess<T>(data: T) {\n return new BizResult(true, '操作成功', data)\n }\n\n static createFail<T>(msg: string = '操作失败', data?: T) {\n return new BizResult(false, msg, data)\n }\n\n static createError<T>(e: unknown) {\n return new BizResult<T>(false, getErrorMessage(e))\n }\n\n /**\n * 展开成Promise\n */\n async toPromise(): Promise<void>\n async toPromise<T>(): Promise<T>\n async toPromise<T = void>(): Promise<T> {\n if (this.success) {\n return this.data as T\n } else {\n throw new CommonError(this.msg)\n }\n }\n}\n\n/**\n * 执行业务(自动包裹BuResult)\n * @param run 执行方法\n */\nexport const execBiz = async <T>(run: () => Promise<T>): Promise<BizResult<T>> => {\n try {\n return BizResult.createSuccess<T>(await run())\n } catch (e) {\n return BizResult.createError(e)\n }\n}\n","/**\n * 是否为空数组\n * @param data\n */\nexport function isEmptyArr(data: unknown) {\n return Array.isArray(data) && data.length === 0\n}\n\n/**\n * 将数组分块为指定大小的多个子数组\n * @param arr 原数组\n * @param size 每个块的长度\n * @example chunk([1,2,3,4,5], 2) => [[1,2],[3,4],[5]]\n */\nexport function chunk<T>(arr: T[], size: number): T[][] {\n if (!Number.isInteger(size) || size < 1) throw new Error('size 必须是正整数')\n const result: T[][] = []\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size))\n }\n return result\n}\n","/**\n * 随机运行参数\n * @param fns\n * @param maxCount 最多执行次数(1 ~ fns.length)\n */\nexport function runRandomFunctions(fns: Array<() => void>, maxCount?: number): void {\n maxCount = maxCount ?? fns.length\n const count = Math.floor(Math.random() * maxCount) + 1\n\n const shuffled = [...fns]\n for (let i = shuffled.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]\n }\n\n const selected = shuffled.slice(0, count)\n\n for (const fn of selected) {\n fn()\n }\n}\n\n/**\n * 将数字范围按批次处理,每个批次调用一次异步函数\n *\n * @param start - 起始值(包含)\n * @param end - 结束值(包含)\n * @param batchSize - 每批最大元素个数\n * @param processor - 处理单批数字数组的异步函数\n *\n * @example\n * // 分批处理 1..10,每批最多 3 个数字\n * await processRangeInBatches(1, 10, 3, async (batch) => {\n * console.log(batch) // 输出: [1,2,3], [4,5,6], [7,8,9], [10]\n * })\n */\nexport async function processRangeInBatches(\n start: number,\n end: number,\n batchSize: number,\n processor: (batch: number[]) => Promise<void>,\n): Promise<void> {\n for (let current = start; current <= end; current += batchSize) {\n const remaining = end - current + 1\n const actualSize = Math.min(batchSize, remaining)\n const batch = Array.from({ length: actualSize }, (_, idx) => current + idx)\n\n await processor(batch)\n }\n}\n","import { CommonError } from '../common/error.js'\nimport type { GithubRepository } from '../types/github.js'\n\n/**\n * 从 url 解析 github 仓库信息\n * @param repositoryUrl 仓库 URL(支持带有git+前缀、具体文件路径)\n */\nexport function parseGithubRepo(repositoryUrl: string): GithubRepository {\n // 去掉 git+ 前缀\n repositoryUrl = repositoryUrl.replace(/^git\\+/, '')\n\n const regexBase = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+?)(?:\\.git|\\/)?$/\n const regexFile = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)\\/blob\\/([^/]+)$/\n\n // 情况 1:git clone 地址 或 repo 根路径\n const m1 = repositoryUrl.match(regexBase)\n if (m1) {\n return {\n owner: m1[1],\n repo: m1[2],\n branch: 'main', // 默认分支 main\n }\n }\n\n // 情况 2:具体文件路径\n const m2 = repositoryUrl.match(regexFile)\n if (m2) {\n return {\n owner: m2[1],\n repo: m2[2],\n branch: m2[3],\n }\n }\n\n throw new CommonError('解析插件仓库URL失败')\n}\n","import { nanoid } from 'nanoid'\n\n/**\n * 生成唯一 id\n */\nexport function generateId(): string {\n return nanoid()\n}\n","import type { NetworkInfo, NetworkState } from '../types/network.js'\n\nfunction isConnection(obj: unknown): obj is NetworkInfo {\n return obj !== null && typeof obj === 'object' && 'downlink' in obj && 'rtt' in obj && 'effectiveType' in obj\n}\n\n/**\n * 获取网络信息\n */\nexport function getNetworkInfo(): NetworkState {\n if (!navigator.onLine) {\n return 'offline'\n }\n\n if ('connection' in navigator && isConnection(navigator.connection)) {\n // 现代 Web API 直接获取网络连接的信息\n const connection = navigator.connection\n return {\n downlink: connection.downlink,\n rtt: connection.rtt,\n effectiveType: connection.effectiveType,\n }\n } else {\n return 'online'\n }\n}\n\n/**\n * 监听网络状态变化\n * @param listener 监听器\n * @returns 成功监听时返回解绑函数\n */\nexport function onNetworkChange(listener: (info: NetworkState) => void) {\n const handleChange = () => {\n listener(getNetworkInfo())\n }\n\n if ('connection' in navigator && isConnection(navigator.connection)) {\n // 现代 Web API\n const connection = navigator.connection\n connection.addEventListener('change', handleChange)\n return () => connection.removeEventListener('change', handleChange)\n } else {\n window.addEventListener('online', handleChange)\n window.addEventListener('offline', handleChange)\n return () => {\n window.removeEventListener('online', handleChange)\n window.removeEventListener('offline', handleChange)\n }\n }\n}\n","/**\n * 数组洗牌\n */\nexport function shuffle<T>(arr: T[]): T[] {\n const clone = arr.slice()\n for (let i = clone.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[clone[i], clone[j]] = [clone[j], clone[i]]\n }\n return clone\n}\n\n/**\n * 获取 [min, max] 的随机整数\n */\nexport function randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\n/**\n * 获取 [min, max) 的随机浮点数\n */\nexport function randomFloat(min: number, max: number): number {\n return Math.random() * (max - min) + min\n}\n\n/**\n * 从数组中随机取若干项,不可重复\n */\nexport function sample<T>(arr: T[], count: number): T[] {\n return shuffle(arr).slice(0, count)\n}\n\n/**\n * 从数组中随机取若干项,可重复\n */\nexport function sampleWithReplacement<T>(arr: T[], count: number): T[] {\n const result: T[] = []\n for (let i = 0; i < count; i++) {\n const index = randomInt(0, arr.length - 1)\n result.push(arr[index])\n }\n return result\n}\n\n/**\n * 从数组中获取随机项\n */\nexport function sampleOne<T>(arr: T[]): T {\n return arr[randomInt(0, arr.length - 1)]\n}\n\n/**\n * 获取 1~n 的随机数\n */\nexport function random1ToN(n: number): number {\n return randomInt(1, n)\n}\n","/**\n * 支持取消的 sleep\n * @param ms 延迟毫秒数\n * @param signal 取消信号\n */\nexport function sleep(ms: number, signal?: AbortSignal) {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) return reject(new Error('取消操作'))\n\n const timer = setTimeout(() => {\n cleanup()\n resolve()\n }, ms)\n\n const onAbort = () => {\n clearTimeout(timer)\n cleanup()\n reject(new Error('取消操作'))\n }\n\n const cleanup = () => {\n signal?.removeEventListener('abort', onAbort)\n }\n\n signal?.addEventListener('abort', onAbort)\n })\n}\n\n/**\n * 支持取消的随机 sleep\n * @param minMS 最小延迟毫秒数\n * @param maxMS 最大延迟毫秒数\n * @param signal 取消信号\n */\nexport function sleepRandom(minMS: number, maxMS: number, signal?: AbortSignal) {\n const ms = Math.random() * (maxMS - minMS) + minMS\n return sleep(ms, signal)\n}\n","import dayjs from 'dayjs'\n\n/**\n * 格式化时间为 2020-02-02 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedDateTime(date?: Date): string {\n return dayjs(date).format('YYYY-MM-DD HH:mm:ss')\n}\n\n/**\n * 格式化时间为 2020-02-02 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedDate(date?: Date): string {\n return dayjs(date).format('YYYY-MM-DD')\n}\n\n/**\n * 格式化时间为 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedTime(date?: Date): string {\n return dayjs(date).format('HH:mm:ss')\n}\n","import type { ParsedUrl } from '../types/utl.js'\n\n/** URL query 中必须编码的保留字符 (RFC 3986) */\nexport const invalidCharRegex = /[!'()*]/g\n\n/** 查询参数 */\nexport type QueryParams = Record<string, string | number | boolean | null | undefined>\n\n/**\n * 判断字符串是否为有效的 HTTP/HTTPS URL\n * @param path - 待检测的字符串\n */\nexport function isHttpUrl(path: string) {\n try {\n const url = new URL(path)\n return url.protocol === 'http:' || url.protocol === 'https:'\n } catch {\n return false\n }\n}\n\n/**\n * 解析 url\n * @param url\n */\nexport function parseUrl(url: string): ParsedUrl {\n try {\n const { origin, pathname, searchParams } = new URL(url)\n return {\n baseUrl: origin + pathname,\n searchParams,\n }\n } catch {\n throw new Error('Invalid URL')\n }\n}\n\n/**\n * 编码 URL 参数\n * @param params 查询参数\n */\nexport function encodeURLParams(params: QueryParams) {\n return (\n Object.keys(params)\n // 排序\n .sort()\n // 编码 key 和 value\n .map((key) => {\n const raw = params[key]\n if (raw === undefined || raw === null) return ''\n\n const value = String(raw).replace(invalidCharRegex, '')\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`\n })\n // 拼接\n .join('&')\n )\n}\n\n/**\n *\n */\n/**\n * 合并查询参数\n * @param urlSearchParams url解析后查询参数\n * @param params 单独传的查询参数\n */\nexport function mergeQueryParams(urlSearchParams: URLSearchParams, params?: QueryParams): QueryParams {\n let mergedParams: QueryParams = {}\n if (urlSearchParams.size > 0) {\n // 合并url里的查询参数\n urlSearchParams.forEach((value, key) => {\n mergedParams[key] = value\n })\n }\n // 处理单独传的查询参数对象\n if (params) {\n mergedParams = { ...mergedParams, ...params }\n }\n return mergedParams\n}\n","/**\n * 生成 CSS `color-mix()` 函数的字符串表示,用于动态计算两种颜色的混合结果\n *\n * @param {string} color1 - 参与混合的第一种颜色(支持 CSS 合法颜色值,如 HEX、RGB、HSL 等)\n * @param {string} color2 - 参与混合的第二种颜色\n * @param {number} percentage - 主颜色(color1)在混合中的占比(百分比数值,范围 0-100)\n * @param {'srgb' | 'hsl'} [colorSpace='srgb'] - 色彩空间选项:\n * - `'srgb'`: 标准 RGB 色彩空间(默认)\n * - `'hsl'`: 色相-饱和度-明度色彩空间\n * @param {number} [percentage2] - 可选参数:副颜色(color2)的独立占比。\n * 若未提供,则自动计算为 `100 - percentage`\n * @returns {string} 可直接用于 CSS 的 `color-mix()` 函数字符串(如 `color-mix(in srgb, red 30%, blue 70%)`)\n *\n * @example\n * // 基础用法(自动计算互补占比)\n * mixColor('red', 'blue', 30)\n * // 返回: \"color-mix(in srgb, red 30%, blue 70%)\"\n *\n * @example\n * // 显式指定双占比 + HSL 色彩空间\n * mixColor('#ff0000', '#0000ff', 40, 'hsl', 60)\n * // 返回: \"color-mix(in hsl, #ff0000 40%, #0000ff 60%)\"\n */\nexport const mixColor = (\n color1: string,\n color2: string,\n percentage: number,\n colorSpace: 'srgb' | 'hsl' = 'srgb',\n percentage2?: number,\n): string => {\n return `color-mix(in ${colorSpace}, ${color1} ${percentage}%, ${color2} ${percentage2 ? percentage2 : 100 - percentage}%)`\n}\n\n/**\n * 将十六进制颜色转换为 RGB\n */\nexport const hexToRgb = (hex: string): { r: number; g: number; b: number } => {\n const r = parseInt(hex.slice(1, 3), 16)\n const g = parseInt(hex.slice(3, 5), 16)\n const b = parseInt(hex.slice(5, 7), 16)\n return { r, g, b }\n}\n","/**\n * 设置 html 根元素的 css 变量\n */\nexport const setCssVar = (k: string, v: string) => {\n document.documentElement.style.setProperty(k, v)\n}\n","/**\n * 等待 <img> 加载完成\n */\nexport function whenImageLoaded(img: HTMLImageElement): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n if (img.dataset['state'] === 'loading') {\n img.src = img.dataset['src']!\n }\n\n if (img.complete && img.naturalWidth > 0) {\n resolve(img)\n return\n }\n\n const onLoad = () => {\n cleanup()\n resolve(img)\n }\n\n const onError = () => {\n cleanup()\n reject(new Error(`图片加载失败: ${img.src}`))\n }\n\n const cleanup = () => {\n img.removeEventListener('load', onLoad)\n img.removeEventListener('error', onError)\n }\n\n img.addEventListener('load', onLoad)\n img.addEventListener('error', onError)\n })\n}\n\n/**\n * 从 <img> 元素获取图片字节数据(ArrayBuffer)\n * @param img 已加载的 <img> 元素\n * @param type 图片类型,可选(默认 png)\n */\nexport async function getImageArrayBuffer(img: HTMLImageElement, type: string = 'image/png'): Promise<ArrayBuffer> {\n const canvas = document.createElement('canvas')\n canvas.width = img.naturalWidth\n canvas.height = img.naturalHeight\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('无法创建 Canvas 2D 上下文')\n ctx.drawImage(img, 0, 0)\n\n const blob: Blob = await new Promise((resolve, reject) => {\n canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('toBlob 失败'))), type)\n })\n\n return await blob.arrayBuffer()\n}\n\n/**\n * 等待加载完成并获取字节数据\n */\nexport async function getImgArrayBufferAfterLoad(img: HTMLImageElement, type?: string): Promise<ArrayBuffer> {\n const loaded = await whenImageLoaded(img)\n return await getImageArrayBuffer(loaded, type)\n}\n","/** 可见性改变的监听器 */\nexport interface VisibilityChangeListener {\n (hidden: boolean): void\n}\n\n/**\n * 监听页面可见性变化(兼容旧的IE/Chrome)\n * @param listener 监听器\n * @returns 成功监听时返回解绑函数\n */\nexport function onVisibilityChange(listener: VisibilityChangeListener) {\n let hiddenPropName: string | undefined = undefined,\n hiddenEventName: string | undefined = undefined\n\n if (typeof document.hidden !== 'undefined') {\n // 现代 Web API\n hiddenPropName = 'hidden'\n hiddenEventName = 'visibilitychange'\n } else if ('msHidden' in document && typeof document.msHidden !== 'undefined') {\n // 旧 IE\n hiddenPropName = 'msHidden'\n hiddenEventName = 'msvisibilitychange'\n } else if ('webkitHidden' in document && typeof document.webkitHidden !== 'undefined') {\n // 旧 Chrome\n hiddenPropName = 'webkitHidden'\n hiddenEventName = 'webkitvisibilitychange'\n }\n\n if (!hiddenPropName || !hiddenEventName) {\n return null\n }\n\n const handler = () => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n listener(document[hiddenPropName])\n }\n\n document.addEventListener(hiddenEventName, handler)\n\n return () => {\n document.removeEventListener(hiddenEventName, handler)\n }\n}\n","/**\n * 滚动元素到屏幕中心\n * @param el\n */\nexport async function humanScrollElIntoCenter(el: HTMLElement) {\n if (!el) return\n\n const rect = el.getBoundingClientRect()\n const doc = document.documentElement\n const body = document.body\n\n const scrollX = window.scrollX || doc.scrollLeft || body.scrollLeft\n const scrollY = window.scrollY || doc.scrollTop || body.scrollTop\n\n const viewW = window.innerWidth\n const viewH = window.innerHeight\n\n // 目标中心点相对页面的位置\n const targetX = rect.left + scrollX + rect.width / 2 - viewW / 2\n const targetY = rect.top + scrollY + rect.height / 2 - viewH / 2\n\n const maxX = Math.max(0, body.scrollWidth - viewW)\n const maxY = Math.max(0, body.scrollHeight - viewH)\n\n // 页面不需要滚动\n if (maxX === 0 && maxY === 0) return\n\n // 水平滚动:仅在可滚动时\n const newX = maxX > 0 ? Math.min(Math.max(targetX, 0), maxX) : scrollX\n // 垂直滚动\n const newY = maxY > 0 ? Math.min(Math.max(targetY, 0), maxY) : scrollY\n\n // 判断是否真正需要滚动\n const needScrollX = Math.abs(window.scrollX - newX) > 1\n const needScrollY = Math.abs(window.scrollY - newY) > 1\n if (!needScrollX && !needScrollY) return\n\n await humanScrollTo(newX, newY)\n}\n\n/**\n * 等待滚动\n */\nexport function waitScrollTo(targetX: number, targetY: number): Promise<void> {\n return new Promise((resolve) => {\n const currentX = window.scrollX\n const currentY = window.scrollY\n\n // 若无需滚动\n if (Math.abs(currentX - targetX) < 1 && Math.abs(currentY - targetY) < 1) {\n resolve()\n return\n }\n\n let timer: number | undefined\n let finished = false\n\n const cleanup = () => {\n if (finished) return\n finished = true\n window.removeEventListener('scroll', handler)\n if (timer) clearTimeout(timer)\n resolve()\n }\n\n const handler = () => {\n if (timer) clearTimeout(timer)\n // 若 50ms 内无新滚动事件,则视为滚动结束\n timer = window.setTimeout(cleanup, 50)\n }\n\n // 启动兜底超时(比如滚动事件根本不触发)\n const failSafe = window.setTimeout(() => {\n console.debug('[waitScrollTo] fallback timeout reached')\n cleanup()\n }, 1000)\n\n const cleanupWithTimeout = () => {\n cleanup()\n clearTimeout(failSafe)\n }\n\n // 替换 cleanup,确保清理超时器\n const finalHandler = () => {\n if (timer) clearTimeout(timer)\n timer = window.setTimeout(cleanupWithTimeout, 50)\n }\n\n // 注册事件\n window.addEventListener('scroll', finalHandler, { passive: true })\n\n // 立即触发滚动\n window.scrollTo({ left: targetX, top: targetY })\n\n // 有时浏览器同步滚动,不触发 scroll 事件\n requestAnimationFrame(() => {\n const nowX = window.scrollX\n const nowY = window.scrollY\n if (Math.abs(nowX - targetX) < 1 && Math.abs(nowY - targetY) < 1) {\n cleanupWithTimeout()\n }\n })\n })\n}\n\n/**\n * 模拟人类手感滚动到指定位置\n */\nexport async function humanScrollTo(targetX: number, targetY: number): Promise<void> {\n return new Promise<void>((resolve) => {\n let currentX = window.scrollX\n let currentY = window.scrollY\n\n async function step() {\n const dx = targetX - currentX\n const dy = targetY - currentY\n\n // 如果距离足够小,直接跳到目标结束\n if (Math.abs(dx) < 1 && Math.abs(dy) < 1) {\n window.scrollTo(targetX, targetY)\n resolve()\n return\n }\n\n // 随机步长 (最小 2px,最大剩余距离的 20%)\n const stepX = Math.sign(dx) * Math.min(Math.max(2, Math.random() * Math.abs(dx) * 0.2), Math.abs(dx))\n const stepY = Math.sign(dy) * Math.min(Math.max(2, Math.random() * Math.abs(dy) * 0.2), Math.abs(dy))\n\n currentX += stepX\n currentY += stepY\n await waitScrollTo(currentX, currentY)\n\n // 随机短暂停顿 10~30ms\n const delay = 10 + Math.random() * 20\n setTimeout(step, delay)\n }\n\n step()\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.cjs","names":[],"sources":["../src/utils/error.ts","../src/common/error.ts","../src/common/biz-result.ts","../src/utils/array.ts","../src/utils/function.ts","../src/utils/github.ts","../src/utils/network.ts","../src/utils/random.ts","../src/utils/sleep.ts","../src/utils/time.ts","../src/utils/url.ts","../src/utils/dom/color.ts","../src/utils/dom/css.ts","../src/utils/dom/img.ts","../src/utils/dom/page.ts","../src/utils/dom/scroll.ts"],"sourcesContent":["import { CommonError } from '../common/error.js'\n\n/**\n * 判断是否为通用异常\n */\nexport function isCommonError(error: unknown): error is CommonError {\n return error instanceof CommonError\n}\n\n/**\n * 设置异常信息的前置提示\n * @param error 异常\n * @param preMsg 前置信息 `${preMsg}${error.message}`\n */\nexport function prependErrorMessage(error: CommonError, preMsg?: string): CommonError {\n if (preMsg) {\n error.message = `${preMsg} ${error.message}`\n }\n return error\n}\n\n/**\n * 转换到通用异常\n * @param error 异常\n * @param preMsg 前置提示 `${preMsg}${error.message}`\n */\nexport function convertToCommonError(error: unknown, preMsg?: string): CommonError {\n if (isCommonError(error)) {\n return prependErrorMessage(error, preMsg)\n }\n if (\n typeof error === 'object' &&\n error !== null &&\n 'message' in error &&\n typeof (error as Record<string, unknown>).message === 'string'\n ) {\n const newError = error as { message: string }\n return prependErrorMessage(new CommonError(newError.message), preMsg)\n } else {\n // 如果抛出的异常不是object\n return prependErrorMessage(new CommonError(String(error)), preMsg)\n }\n}\n\n/**\n * 获取异常信息\n */\nexport function getErrorMessage(error: unknown): string {\n return convertToCommonError(error).message\n}\n","import { getErrorMessage } from '../utils/error.js'\n\n/**\n * 通用异常\n */\nexport class CommonError extends Error {\n // 异常信息\n message: string\n // 原始异常\n rawError?: Error\n\n constructor(message: string, rawError?: Error) {\n super(message)\n this.message = rawError ? `${message} ${getErrorMessage(rawError)}` : message\n this.rawError = rawError\n }\n}\n\n/**\n * 中止异常\n */\nexport class AbortError extends CommonError {\n constructor() {\n super('操作已取消')\n }\n}\n","import { CommonError } from './error.js'\nimport { getErrorMessage } from '../utils/error.js'\n\n/**\n * 业务执行结果\n */\nexport class BizResult<T> {\n success: boolean\n msg: string\n data?: T\n\n constructor(success: boolean, msg: string, data?: T) {\n this.success = success\n this.msg = msg\n this.data = data\n }\n\n static createSuccess<T>(data: T) {\n return new BizResult(true, '操作成功', data)\n }\n\n static createFail<T>(msg: string = '操作失败', data?: T) {\n return new BizResult(false, msg, data)\n }\n\n static createError<T>(e: unknown) {\n return new BizResult<T>(false, getErrorMessage(e))\n }\n\n /**\n * 展开成Promise\n */\n async toPromise(): Promise<void>\n async toPromise<T>(): Promise<T>\n async toPromise<T = void>(): Promise<T> {\n if (this.success) {\n return this.data as T\n } else {\n throw new CommonError(this.msg)\n }\n }\n}\n\n/**\n * 执行业务(自动包裹BuResult)\n * @param run 执行方法\n */\nexport const execBiz = async <T>(run: () => Promise<T>): Promise<BizResult<T>> => {\n try {\n return BizResult.createSuccess<T>(await run())\n } catch (e) {\n return BizResult.createError(e)\n }\n}\n","/**\n * 是否为空数组\n * @param data\n */\nexport function isEmptyArr(data: unknown) {\n return Array.isArray(data) && data.length === 0\n}\n\n/**\n * 将数组分块为指定大小的多个子数组\n * @param arr 原数组\n * @param size 每个块的长度\n * @example chunk([1,2,3,4,5], 2) => [[1,2],[3,4],[5]]\n */\nexport function chunk<T>(arr: T[], size: number): T[][] {\n if (!Number.isInteger(size) || size < 1) throw new Error('size 必须是正整数')\n const result: T[][] = []\n for (let i = 0; i < arr.length; i += size) {\n result.push(arr.slice(i, i + size))\n }\n return result\n}\n","/**\n * 随机运行参数\n * @param fns\n * @param maxCount 最多执行次数(1 ~ fns.length)\n */\nexport function runRandomFunctions(fns: Array<() => void>, maxCount?: number): void {\n maxCount = maxCount ?? fns.length\n const count = Math.floor(Math.random() * maxCount) + 1\n\n const shuffled = [...fns]\n for (let i = shuffled.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]\n }\n\n const selected = shuffled.slice(0, count)\n\n for (const fn of selected) {\n fn()\n }\n}\n\n/**\n * 将数字范围按批次处理,每个批次调用一次异步函数\n *\n * @param start - 起始值(包含)\n * @param end - 结束值(包含)\n * @param batchSize - 每批最大元素个数\n * @param processor - 处理单批数字数组的异步函数\n *\n * @example\n * // 分批处理 1..10,每批最多 3 个数字\n * await processRangeInBatches(1, 10, 3, async (batch) => {\n * console.log(batch) // 输出: [1,2,3], [4,5,6], [7,8,9], [10]\n * })\n */\nexport async function processRangeInBatches(\n start: number,\n end: number,\n batchSize: number,\n processor: (batch: number[]) => Promise<void>,\n): Promise<void> {\n for (let current = start; current <= end; current += batchSize) {\n const remaining = end - current + 1\n const actualSize = Math.min(batchSize, remaining)\n const batch = Array.from({ length: actualSize }, (_, idx) => current + idx)\n\n await processor(batch)\n }\n}\n","import { CommonError } from '../common/error.js'\nimport type { GithubRepository } from '../types/github.js'\n\n/**\n * 从 url 解析 github 仓库信息\n * @param repositoryUrl 仓库 URL(支持带有git+前缀、具体文件路径)\n */\nexport function parseGithubRepo(repositoryUrl: string): GithubRepository {\n // 去掉 git+ 前缀\n repositoryUrl = repositoryUrl.replace(/^git\\+/, '')\n\n const regexBase = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+?)(?:\\.git|\\/)?$/\n const regexFile = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)\\/blob\\/([^/]+)$/\n\n // 情况 1:git clone 地址 或 repo 根路径\n const m1 = repositoryUrl.match(regexBase)\n if (m1) {\n return {\n owner: m1[1],\n repo: m1[2],\n branch: 'main', // 默认分支 main\n }\n }\n\n // 情况 2:具体文件路径\n const m2 = repositoryUrl.match(regexFile)\n if (m2) {\n return {\n owner: m2[1],\n repo: m2[2],\n branch: m2[3],\n }\n }\n\n throw new CommonError('解析插件仓库URL失败')\n}\n","import type { NetworkInfo, NetworkState } from '../types/network.js'\n\nfunction isConnection(obj: unknown): obj is NetworkInfo {\n return obj !== null && typeof obj === 'object' && 'downlink' in obj && 'rtt' in obj && 'effectiveType' in obj\n}\n\n/**\n * 获取网络信息\n */\nexport function getNetworkInfo(): NetworkState {\n if (!navigator.onLine) {\n return 'offline'\n }\n\n if ('connection' in navigator && isConnection(navigator.connection)) {\n // 现代 Web API 直接获取网络连接的信息\n const connection = navigator.connection\n return {\n downlink: connection.downlink,\n rtt: connection.rtt,\n effectiveType: connection.effectiveType,\n }\n } else {\n return 'online'\n }\n}\n\n/**\n * 监听网络状态变化\n * @param listener 监听器\n * @returns 成功监听时返回解绑函数\n */\nexport function onNetworkChange(listener: (info: NetworkState) => void) {\n const handleChange = () => {\n listener(getNetworkInfo())\n }\n\n if ('connection' in navigator && isConnection(navigator.connection)) {\n // 现代 Web API\n const connection = navigator.connection\n connection.addEventListener('change', handleChange)\n return () => connection.removeEventListener('change', handleChange)\n } else {\n window.addEventListener('online', handleChange)\n window.addEventListener('offline', handleChange)\n return () => {\n window.removeEventListener('online', handleChange)\n window.removeEventListener('offline', handleChange)\n }\n }\n}\n","/**\n * 数组洗牌\n */\nexport function shuffle<T>(arr: T[]): T[] {\n const clone = arr.slice()\n for (let i = clone.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[clone[i], clone[j]] = [clone[j], clone[i]]\n }\n return clone\n}\n\n/**\n * 获取 [min, max] 的随机整数\n */\nexport function randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\n/**\n * 获取 [min, max) 的随机浮点数\n */\nexport function randomFloat(min: number, max: number): number {\n return Math.random() * (max - min) + min\n}\n\n/**\n * 从数组中随机取若干项,不可重复\n */\nexport function sample<T>(arr: T[], count: number): T[] {\n return shuffle(arr).slice(0, count)\n}\n\n/**\n * 从数组中随机取若干项,可重复\n */\nexport function sampleWithReplacement<T>(arr: T[], count: number): T[] {\n const result: T[] = []\n for (let i = 0; i < count; i++) {\n const index = randomInt(0, arr.length - 1)\n result.push(arr[index])\n }\n return result\n}\n\n/**\n * 从数组中获取随机项\n */\nexport function sampleOne<T>(arr: T[]): T {\n return arr[randomInt(0, arr.length - 1)]\n}\n\n/**\n * 获取 1~n 的随机数\n */\nexport function random1ToN(n: number): number {\n return randomInt(1, n)\n}\n","/**\n * 支持取消的 sleep\n * @param ms 延迟毫秒数\n * @param signal 取消信号\n */\nexport function sleep(ms: number, signal?: AbortSignal) {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) return reject(new Error('取消操作'))\n\n const timer = setTimeout(() => {\n cleanup()\n resolve()\n }, ms)\n\n const onAbort = () => {\n clearTimeout(timer)\n cleanup()\n reject(new Error('取消操作'))\n }\n\n const cleanup = () => {\n signal?.removeEventListener('abort', onAbort)\n }\n\n signal?.addEventListener('abort', onAbort)\n })\n}\n\n/**\n * 支持取消的随机 sleep\n * @param minMS 最小延迟毫秒数\n * @param maxMS 最大延迟毫秒数\n * @param signal 取消信号\n */\nexport function sleepRandom(minMS: number, maxMS: number, signal?: AbortSignal) {\n const ms = Math.random() * (maxMS - minMS) + minMS\n return sleep(ms, signal)\n}\n","import dayjs from 'dayjs'\n\n/**\n * 格式化时间为 2020-02-02 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedDateTime(date?: Date): string {\n return dayjs(date).format('YYYY-MM-DD HH:mm:ss')\n}\n\n/**\n * 格式化时间为 2020-02-02 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedDate(date?: Date): string {\n return dayjs(date).format('YYYY-MM-DD')\n}\n\n/**\n * 格式化时间为 20:20:20 的字符串\n * @param date 需要格式化的时间,为空则获取当前时间\n */\nexport function getFormattedTime(date?: Date): string {\n return dayjs(date).format('HH:mm:ss')\n}\n","import type { ParsedUrl } from '../types/utl.js'\n\n/** URL query 中必须编码的保留字符 (RFC 3986) */\nexport const invalidCharRegex = /[!'()*]/g\n\n/** 查询参数 */\nexport type QueryParams = Record<string, string | number | boolean | null | undefined>\n\n/**\n * 判断字符串是否为有效的 HTTP/HTTPS URL\n * @param path - 待检测的字符串\n */\nexport function isHttpUrl(path: string) {\n try {\n const url = new URL(path)\n return url.protocol === 'http:' || url.protocol === 'https:'\n } catch {\n return false\n }\n}\n\n/**\n * 解析 url\n * @param url\n */\nexport function parseUrl(url: string): ParsedUrl {\n try {\n const { origin, pathname, searchParams } = new URL(url)\n return {\n baseUrl: origin + pathname,\n searchParams,\n }\n } catch {\n throw new Error('Invalid URL')\n }\n}\n\n/**\n * 编码 URL 参数\n * @param params 查询参数\n */\nexport function encodeURLParams(params: QueryParams) {\n return (\n Object.keys(params)\n // 排序\n .sort()\n // 编码 key 和 value\n .map((key) => {\n const raw = params[key]\n if (raw === undefined || raw === null) return ''\n\n const value = String(raw).replace(invalidCharRegex, '')\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`\n })\n // 拼接\n .join('&')\n )\n}\n\n/**\n *\n */\n/**\n * 合并查询参数\n * @param urlSearchParams url解析后查询参数\n * @param params 单独传的查询参数\n */\nexport function mergeQueryParams(urlSearchParams: URLSearchParams, params?: QueryParams): QueryParams {\n let mergedParams: QueryParams = {}\n if (urlSearchParams.size > 0) {\n // 合并url里的查询参数\n urlSearchParams.forEach((value, key) => {\n mergedParams[key] = value\n })\n }\n // 处理单独传的查询参数对象\n if (params) {\n mergedParams = { ...mergedParams, ...params }\n }\n return mergedParams\n}\n","/**\n * 生成 CSS `color-mix()` 函数的字符串表示,用于动态计算两种颜色的混合结果\n *\n * @param {string} color1 - 参与混合的第一种颜色(支持 CSS 合法颜色值,如 HEX、RGB、HSL 等)\n * @param {string} color2 - 参与混合的第二种颜色\n * @param {number} percentage - 主颜色(color1)在混合中的占比(百分比数值,范围 0-100)\n * @param {'srgb' | 'hsl'} [colorSpace='srgb'] - 色彩空间选项:\n * - `'srgb'`: 标准 RGB 色彩空间(默认)\n * - `'hsl'`: 色相-饱和度-明度色彩空间\n * @param {number} [percentage2] - 可选参数:副颜色(color2)的独立占比。\n * 若未提供,则自动计算为 `100 - percentage`\n * @returns {string} 可直接用于 CSS 的 `color-mix()` 函数字符串(如 `color-mix(in srgb, red 30%, blue 70%)`)\n *\n * @example\n * // 基础用法(自动计算互补占比)\n * mixColor('red', 'blue', 30)\n * // 返回: \"color-mix(in srgb, red 30%, blue 70%)\"\n *\n * @example\n * // 显式指定双占比 + HSL 色彩空间\n * mixColor('#ff0000', '#0000ff', 40, 'hsl', 60)\n * // 返回: \"color-mix(in hsl, #ff0000 40%, #0000ff 60%)\"\n */\nexport const mixColor = (\n color1: string,\n color2: string,\n percentage: number,\n colorSpace: 'srgb' | 'hsl' = 'srgb',\n percentage2?: number,\n): string => {\n return `color-mix(in ${colorSpace}, ${color1} ${percentage}%, ${color2} ${percentage2 ? percentage2 : 100 - percentage}%)`\n}\n\n/**\n * 将十六进制颜色转换为 RGB\n */\nexport const hexToRgb = (hex: string): { r: number; g: number; b: number } => {\n const r = parseInt(hex.slice(1, 3), 16)\n const g = parseInt(hex.slice(3, 5), 16)\n const b = parseInt(hex.slice(5, 7), 16)\n return { r, g, b }\n}\n","/**\n * 设置 html 根元素的 css 变量\n */\nexport const setCssVar = (k: string, v: string) => {\n document.documentElement.style.setProperty(k, v)\n}\n","/**\n * 等待 <img> 加载完成\n */\nexport function whenImageLoaded(img: HTMLImageElement): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n if (img.dataset['state'] === 'loading') {\n img.src = img.dataset['src']!\n }\n\n if (img.complete && img.naturalWidth > 0) {\n resolve(img)\n return\n }\n\n const onLoad = () => {\n cleanup()\n resolve(img)\n }\n\n const onError = () => {\n cleanup()\n reject(new Error(`图片加载失败: ${img.src}`))\n }\n\n const cleanup = () => {\n img.removeEventListener('load', onLoad)\n img.removeEventListener('error', onError)\n }\n\n img.addEventListener('load', onLoad)\n img.addEventListener('error', onError)\n })\n}\n\n/**\n * 从 <img> 元素获取图片字节数据(ArrayBuffer)\n * @param img 已加载的 <img> 元素\n * @param type 图片类型,可选(默认 png)\n */\nexport async function getImageArrayBuffer(img: HTMLImageElement, type: string = 'image/png'): Promise<ArrayBuffer> {\n const canvas = document.createElement('canvas')\n canvas.width = img.naturalWidth\n canvas.height = img.naturalHeight\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('无法创建 Canvas 2D 上下文')\n ctx.drawImage(img, 0, 0)\n\n const blob: Blob = await new Promise((resolve, reject) => {\n canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('toBlob 失败'))), type)\n })\n\n return await blob.arrayBuffer()\n}\n\n/**\n * 等待加载完成并获取字节数据\n */\nexport async function getImgArrayBufferAfterLoad(img: HTMLImageElement, type?: string): Promise<ArrayBuffer> {\n const loaded = await whenImageLoaded(img)\n return await getImageArrayBuffer(loaded, type)\n}\n","/** 可见性改变的监听器 */\nexport interface VisibilityChangeListener {\n (hidden: boolean): void\n}\n\n/**\n * 监听页面可见性变化(兼容旧的IE/Chrome)\n * @param listener 监听器\n * @returns 成功监听时返回解绑函数\n */\nexport function onVisibilityChange(listener: VisibilityChangeListener) {\n let hiddenPropName: string | undefined = undefined,\n hiddenEventName: string | undefined = undefined\n\n if (typeof document.hidden !== 'undefined') {\n // 现代 Web API\n hiddenPropName = 'hidden'\n hiddenEventName = 'visibilitychange'\n } else if ('msHidden' in document && typeof document.msHidden !== 'undefined') {\n // 旧 IE\n hiddenPropName = 'msHidden'\n hiddenEventName = 'msvisibilitychange'\n } else if ('webkitHidden' in document && typeof document.webkitHidden !== 'undefined') {\n // 旧 Chrome\n hiddenPropName = 'webkitHidden'\n hiddenEventName = 'webkitvisibilitychange'\n }\n\n if (!hiddenPropName || !hiddenEventName) {\n return null\n }\n\n const handler = () => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n listener(document[hiddenPropName])\n }\n\n document.addEventListener(hiddenEventName, handler)\n\n return () => {\n document.removeEventListener(hiddenEventName, handler)\n }\n}\n","/**\n * 滚动元素到屏幕中心\n * @param el\n */\nexport async function humanScrollElIntoCenter(el: HTMLElement) {\n if (!el) return\n\n const rect = el.getBoundingClientRect()\n const doc = document.documentElement\n const body = document.body\n\n const scrollX = window.scrollX || doc.scrollLeft || body.scrollLeft\n const scrollY = window.scrollY || doc.scrollTop || body.scrollTop\n\n const viewW = window.innerWidth\n const viewH = window.innerHeight\n\n // 目标中心点相对页面的位置\n const targetX = rect.left + scrollX + rect.width / 2 - viewW / 2\n const targetY = rect.top + scrollY + rect.height / 2 - viewH / 2\n\n const maxX = Math.max(0, body.scrollWidth - viewW)\n const maxY = Math.max(0, body.scrollHeight - viewH)\n\n // 页面不需要滚动\n if (maxX === 0 && maxY === 0) return\n\n // 水平滚动:仅在可滚动时\n const newX = maxX > 0 ? Math.min(Math.max(targetX, 0), maxX) : scrollX\n // 垂直滚动\n const newY = maxY > 0 ? Math.min(Math.max(targetY, 0), maxY) : scrollY\n\n // 判断是否真正需要滚动\n const needScrollX = Math.abs(window.scrollX - newX) > 1\n const needScrollY = Math.abs(window.scrollY - newY) > 1\n if (!needScrollX && !needScrollY) return\n\n await humanScrollTo(newX, newY)\n}\n\n/**\n * 等待滚动\n */\nexport function waitScrollTo(targetX: number, targetY: number): Promise<void> {\n return new Promise((resolve) => {\n const currentX = window.scrollX\n const currentY = window.scrollY\n\n // 若无需滚动\n if (Math.abs(currentX - targetX) < 1 && Math.abs(currentY - targetY) < 1) {\n resolve()\n return\n }\n\n let timer: number | undefined\n let finished = false\n\n const cleanup = () => {\n if (finished) return\n finished = true\n window.removeEventListener('scroll', handler)\n if (timer) clearTimeout(timer)\n resolve()\n }\n\n const handler = () => {\n if (timer) clearTimeout(timer)\n // 若 50ms 内无新滚动事件,则视为滚动结束\n timer = window.setTimeout(cleanup, 50)\n }\n\n // 启动兜底超时(比如滚动事件根本不触发)\n const failSafe = window.setTimeout(() => {\n console.debug('[waitScrollTo] fallback timeout reached')\n cleanup()\n }, 1000)\n\n const cleanupWithTimeout = () => {\n cleanup()\n clearTimeout(failSafe)\n }\n\n // 替换 cleanup,确保清理超时器\n const finalHandler = () => {\n if (timer) clearTimeout(timer)\n timer = window.setTimeout(cleanupWithTimeout, 50)\n }\n\n // 注册事件\n window.addEventListener('scroll', finalHandler, { passive: true })\n\n // 立即触发滚动\n window.scrollTo({ left: targetX, top: targetY })\n\n // 有时浏览器同步滚动,不触发 scroll 事件\n requestAnimationFrame(() => {\n const nowX = window.scrollX\n const nowY = window.scrollY\n if (Math.abs(nowX - targetX) < 1 && Math.abs(nowY - targetY) < 1) {\n cleanupWithTimeout()\n }\n })\n })\n}\n\n/**\n * 模拟人类手感滚动到指定位置\n */\nexport async function humanScrollTo(targetX: number, targetY: number): Promise<void> {\n return new Promise<void>((resolve) => {\n let currentX = window.scrollX\n let currentY = window.scrollY\n\n async function step() {\n const dx = targetX - currentX\n const dy = targetY - currentY\n\n // 如果距离足够小,直接跳到目标结束\n if (Math.abs(dx) < 1 && Math.abs(dy) < 1) {\n window.scrollTo(targetX, targetY)\n resolve()\n return\n }\n\n // 随机步长 (最小 2px,最大剩余距离的 20%)\n const stepX = Math.sign(dx) * Math.min(Math.max(2, Math.random() * Math.abs(dx) * 0.2), Math.abs(dx))\n const stepY = Math.sign(dy) * Math.min(Math.max(2, Math.random() * Math.abs(dy) * 0.2), Math.abs(dy))\n\n currentX += stepX\n currentY += stepY\n await waitScrollTo(currentX, currentY)\n\n // 随机短暂停顿 10~30ms\n const delay = 10 + Math.random() * 20\n setTimeout(step, delay)\n }\n\n step()\n })\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ybgnb/utils",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "author": "hzhilong",
5
5
  "private": false,
6
6
  "description": "自用工具库",
@@ -52,7 +52,6 @@
52
52
  "vite-plugin-dts": "^4.5.4"
53
53
  },
54
54
  "peerDependencies": {
55
- "dayjs": "^1.11.13",
56
- "nanoid": "^5.1.9"
55
+ "dayjs": "^1.11.13"
57
56
  }
58
57
  }