@ybgnb/utils 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/core.cjs +504 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +369 -0
- package/dist/core.d.ts +369 -0
- package/dist/core.js +437 -0
- package/dist/core.js.map +1 -0
- package/dist/dom.cjs +263 -0
- package/dist/dom.cjs.map +1 -0
- package/dist/dom.d.cts +105 -0
- package/dist/dom.d.ts +105 -0
- package/dist/dom.js +225 -0
- package/dist/dom.js.map +1 -0
- package/dist/node.cjs +410 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +153 -0
- package/dist/node.d.ts +153 -0
- package/dist/node.js +350 -0
- package/dist/node.js.map +1 -0
- package/package.json +26 -15
- package/dist/index.d.ts +0 -444
- package/dist/index.js +0 -388
- package/dist/index.js.map +0 -1
- package/dist/index.umd.cjs +0 -2
- package/dist/index.umd.cjs.map +0 -1
package/dist/dom.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// src/dom/utils/color.ts
|
|
2
|
+
var mixColor = (color1, color2, percentage, colorSpace = "srgb", percentage2) => {
|
|
3
|
+
return `color-mix(in ${colorSpace}, ${color1} ${percentage}%, ${color2} ${percentage2 ? percentage2 : 100 - percentage}%)`;
|
|
4
|
+
};
|
|
5
|
+
var hexToRgb = (hex) => {
|
|
6
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
7
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
8
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
9
|
+
return { r, g, b };
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/dom/utils/css.ts
|
|
13
|
+
var setCssVar = (k, v) => {
|
|
14
|
+
document.documentElement.style.setProperty(k, v);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/dom/utils/img.ts
|
|
18
|
+
function whenImageLoaded(img) {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
if (img.dataset["state"] === "loading") {
|
|
21
|
+
img.src = img.dataset["src"];
|
|
22
|
+
}
|
|
23
|
+
if (img.complete && img.naturalWidth > 0) {
|
|
24
|
+
resolve(img);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const onLoad = () => {
|
|
28
|
+
cleanup();
|
|
29
|
+
resolve(img);
|
|
30
|
+
};
|
|
31
|
+
const onError = () => {
|
|
32
|
+
cleanup();
|
|
33
|
+
reject(new Error(`\u56FE\u7247\u52A0\u8F7D\u5931\u8D25: ${img.src}`));
|
|
34
|
+
};
|
|
35
|
+
const cleanup = () => {
|
|
36
|
+
img.removeEventListener("load", onLoad);
|
|
37
|
+
img.removeEventListener("error", onError);
|
|
38
|
+
};
|
|
39
|
+
img.addEventListener("load", onLoad);
|
|
40
|
+
img.addEventListener("error", onError);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function getImageArrayBuffer(img, type = "image/png") {
|
|
44
|
+
const canvas = document.createElement("canvas");
|
|
45
|
+
canvas.width = img.naturalWidth;
|
|
46
|
+
canvas.height = img.naturalHeight;
|
|
47
|
+
const ctx = canvas.getContext("2d");
|
|
48
|
+
if (!ctx) throw new Error("\u65E0\u6CD5\u521B\u5EFA Canvas 2D \u4E0A\u4E0B\u6587");
|
|
49
|
+
ctx.drawImage(img, 0, 0);
|
|
50
|
+
const blob = await new Promise((resolve, reject) => {
|
|
51
|
+
canvas.toBlob((b) => b ? resolve(b) : reject(new Error("toBlob \u5931\u8D25")), type);
|
|
52
|
+
});
|
|
53
|
+
return await blob.arrayBuffer();
|
|
54
|
+
}
|
|
55
|
+
async function getImgArrayBufferAfterLoad(img, type) {
|
|
56
|
+
const loaded = await whenImageLoaded(img);
|
|
57
|
+
return await getImageArrayBuffer(loaded, type);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/dom/utils/network.ts
|
|
61
|
+
function isConnection(obj) {
|
|
62
|
+
return obj !== null && typeof obj === "object" && "downlink" in obj && "rtt" in obj && "effectiveType" in obj;
|
|
63
|
+
}
|
|
64
|
+
function getNetworkInfo() {
|
|
65
|
+
if (!navigator.onLine) {
|
|
66
|
+
return "offline";
|
|
67
|
+
}
|
|
68
|
+
if ("connection" in navigator && isConnection(navigator.connection)) {
|
|
69
|
+
const connection = navigator.connection;
|
|
70
|
+
return {
|
|
71
|
+
downlink: connection.downlink,
|
|
72
|
+
rtt: connection.rtt,
|
|
73
|
+
effectiveType: connection.effectiveType
|
|
74
|
+
};
|
|
75
|
+
} else {
|
|
76
|
+
return "online";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function onNetworkChange(listener) {
|
|
80
|
+
const handleChange = () => {
|
|
81
|
+
listener(getNetworkInfo());
|
|
82
|
+
};
|
|
83
|
+
if ("connection" in navigator && isConnection(navigator.connection)) {
|
|
84
|
+
const connection = navigator.connection;
|
|
85
|
+
connection.addEventListener("change", handleChange);
|
|
86
|
+
return () => connection.removeEventListener("change", handleChange);
|
|
87
|
+
} else {
|
|
88
|
+
window.addEventListener("online", handleChange);
|
|
89
|
+
window.addEventListener("offline", handleChange);
|
|
90
|
+
return () => {
|
|
91
|
+
window.removeEventListener("online", handleChange);
|
|
92
|
+
window.removeEventListener("offline", handleChange);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/dom/utils/page.ts
|
|
98
|
+
function onVisibilityChange(listener) {
|
|
99
|
+
let hiddenPropName = void 0, hiddenEventName = void 0;
|
|
100
|
+
if (typeof document.hidden !== "undefined") {
|
|
101
|
+
hiddenPropName = "hidden";
|
|
102
|
+
hiddenEventName = "visibilitychange";
|
|
103
|
+
} else if ("msHidden" in document && typeof document.msHidden !== "undefined") {
|
|
104
|
+
hiddenPropName = "msHidden";
|
|
105
|
+
hiddenEventName = "msvisibilitychange";
|
|
106
|
+
} else if ("webkitHidden" in document && typeof document.webkitHidden !== "undefined") {
|
|
107
|
+
hiddenPropName = "webkitHidden";
|
|
108
|
+
hiddenEventName = "webkitvisibilitychange";
|
|
109
|
+
}
|
|
110
|
+
if (!hiddenPropName || !hiddenEventName) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const handler = () => {
|
|
114
|
+
listener(document[hiddenPropName]);
|
|
115
|
+
};
|
|
116
|
+
document.addEventListener(hiddenEventName, handler);
|
|
117
|
+
return () => {
|
|
118
|
+
document.removeEventListener(hiddenEventName, handler);
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/dom/utils/scroll.ts
|
|
123
|
+
async function humanScrollElIntoCenter(el) {
|
|
124
|
+
if (!el) return;
|
|
125
|
+
const rect = el.getBoundingClientRect();
|
|
126
|
+
const doc = document.documentElement;
|
|
127
|
+
const body = document.body;
|
|
128
|
+
const scrollX = window.scrollX || doc.scrollLeft || body.scrollLeft;
|
|
129
|
+
const scrollY = window.scrollY || doc.scrollTop || body.scrollTop;
|
|
130
|
+
const viewW = window.innerWidth;
|
|
131
|
+
const viewH = window.innerHeight;
|
|
132
|
+
const targetX = rect.left + scrollX + rect.width / 2 - viewW / 2;
|
|
133
|
+
const targetY = rect.top + scrollY + rect.height / 2 - viewH / 2;
|
|
134
|
+
const maxX = Math.max(0, body.scrollWidth - viewW);
|
|
135
|
+
const maxY = Math.max(0, body.scrollHeight - viewH);
|
|
136
|
+
if (maxX === 0 && maxY === 0) return;
|
|
137
|
+
const newX = maxX > 0 ? Math.min(Math.max(targetX, 0), maxX) : scrollX;
|
|
138
|
+
const newY = maxY > 0 ? Math.min(Math.max(targetY, 0), maxY) : scrollY;
|
|
139
|
+
const needScrollX = Math.abs(window.scrollX - newX) > 1;
|
|
140
|
+
const needScrollY = Math.abs(window.scrollY - newY) > 1;
|
|
141
|
+
if (!needScrollX && !needScrollY) return;
|
|
142
|
+
await humanScrollTo(newX, newY);
|
|
143
|
+
}
|
|
144
|
+
function waitScrollTo(targetX, targetY) {
|
|
145
|
+
return new Promise((resolve) => {
|
|
146
|
+
const currentX = window.scrollX;
|
|
147
|
+
const currentY = window.scrollY;
|
|
148
|
+
if (Math.abs(currentX - targetX) < 1 && Math.abs(currentY - targetY) < 1) {
|
|
149
|
+
resolve();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
let timer;
|
|
153
|
+
let finished = false;
|
|
154
|
+
const cleanup = () => {
|
|
155
|
+
if (finished) return;
|
|
156
|
+
finished = true;
|
|
157
|
+
window.removeEventListener("scroll", handler);
|
|
158
|
+
if (timer) clearTimeout(timer);
|
|
159
|
+
resolve();
|
|
160
|
+
};
|
|
161
|
+
const handler = () => {
|
|
162
|
+
if (timer) clearTimeout(timer);
|
|
163
|
+
timer = window.setTimeout(cleanup, 50);
|
|
164
|
+
};
|
|
165
|
+
const failSafe = window.setTimeout(() => {
|
|
166
|
+
console.debug("[waitScrollTo] fallback timeout reached");
|
|
167
|
+
cleanup();
|
|
168
|
+
}, 1e3);
|
|
169
|
+
const cleanupWithTimeout = () => {
|
|
170
|
+
cleanup();
|
|
171
|
+
clearTimeout(failSafe);
|
|
172
|
+
};
|
|
173
|
+
const finalHandler = () => {
|
|
174
|
+
if (timer) clearTimeout(timer);
|
|
175
|
+
timer = window.setTimeout(cleanupWithTimeout, 50);
|
|
176
|
+
};
|
|
177
|
+
window.addEventListener("scroll", finalHandler, { passive: true });
|
|
178
|
+
window.scrollTo({ left: targetX, top: targetY });
|
|
179
|
+
requestAnimationFrame(() => {
|
|
180
|
+
const nowX = window.scrollX;
|
|
181
|
+
const nowY = window.scrollY;
|
|
182
|
+
if (Math.abs(nowX - targetX) < 1 && Math.abs(nowY - targetY) < 1) {
|
|
183
|
+
cleanupWithTimeout();
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
async function humanScrollTo(targetX, targetY) {
|
|
189
|
+
return new Promise((resolve) => {
|
|
190
|
+
let currentX = window.scrollX;
|
|
191
|
+
let currentY = window.scrollY;
|
|
192
|
+
async function step() {
|
|
193
|
+
const dx = targetX - currentX;
|
|
194
|
+
const dy = targetY - currentY;
|
|
195
|
+
if (Math.abs(dx) < 1 && Math.abs(dy) < 1) {
|
|
196
|
+
window.scrollTo(targetX, targetY);
|
|
197
|
+
resolve();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const stepX = Math.sign(dx) * Math.min(Math.max(2, Math.random() * Math.abs(dx) * 0.2), Math.abs(dx));
|
|
201
|
+
const stepY = Math.sign(dy) * Math.min(Math.max(2, Math.random() * Math.abs(dy) * 0.2), Math.abs(dy));
|
|
202
|
+
currentX += stepX;
|
|
203
|
+
currentY += stepY;
|
|
204
|
+
await waitScrollTo(currentX, currentY);
|
|
205
|
+
const delay = 10 + Math.random() * 20;
|
|
206
|
+
setTimeout(step, delay);
|
|
207
|
+
}
|
|
208
|
+
step();
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
export {
|
|
212
|
+
getImageArrayBuffer,
|
|
213
|
+
getImgArrayBufferAfterLoad,
|
|
214
|
+
getNetworkInfo,
|
|
215
|
+
hexToRgb,
|
|
216
|
+
humanScrollElIntoCenter,
|
|
217
|
+
humanScrollTo,
|
|
218
|
+
mixColor,
|
|
219
|
+
onNetworkChange,
|
|
220
|
+
onVisibilityChange,
|
|
221
|
+
setCssVar,
|
|
222
|
+
waitScrollTo,
|
|
223
|
+
whenImageLoaded
|
|
224
|
+
};
|
|
225
|
+
//# sourceMappingURL=dom.js.map
|
package/dist/dom.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dom/utils/color.ts","../src/dom/utils/css.ts","../src/dom/utils/img.ts","../src/dom/utils/network.ts","../src/dom/utils/page.ts","../src/dom/utils/scroll.ts"],"sourcesContent":["/**\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","/**\n * 网络信息\n */\nexport interface NetworkInfo extends EventTarget {\n // 带宽(估算)\n downlink: number\n // 延迟(估算)\n rtt: number\n // 类型(估算)\n effectiveType: 'slow-2g' | '2g' | '3g' | '4g'\n}\n\n/**\n * 网络状态\n * - 'offline': 无网络\n * - 'online': 在线但不支持 NetworkInformation API\n * - NetworkInformation: 含详细网络信息\n */\nexport type NetworkState = 'offline' | Omit<NetworkInfo, keyof EventTarget> | 'online'\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","/** 可见性改变的监听器 */\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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","names":[]}
|
package/dist/node.cjs
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/node/index.ts
|
|
31
|
+
var node_exports = {};
|
|
32
|
+
__export(node_exports, {
|
|
33
|
+
copyFile: () => copyFile,
|
|
34
|
+
deleteFiles: () => deleteFiles,
|
|
35
|
+
downloadFile: () => downloadFile,
|
|
36
|
+
emptyDirectory: () => emptyDirectory,
|
|
37
|
+
ensureDir: () => ensureDir,
|
|
38
|
+
ensureDirSync: () => ensureDirSync,
|
|
39
|
+
execWinCmd: () => execWinCmd,
|
|
40
|
+
existsFile: () => existsFile,
|
|
41
|
+
exportRegedit: () => exportRegedit,
|
|
42
|
+
findFiles: () => findFiles,
|
|
43
|
+
findFilesByPrefixAndSuffix: () => findFilesByPrefixAndSuffix,
|
|
44
|
+
formatFileSizeFromKB: () => formatFileSizeFromKB,
|
|
45
|
+
getDirSize: () => getDirSize,
|
|
46
|
+
getEnv: () => getEnv,
|
|
47
|
+
getFileSizeKB: () => getFileSizeKB,
|
|
48
|
+
importRegedit: () => importRegedit,
|
|
49
|
+
isFile: () => isFile,
|
|
50
|
+
isFileNotFoundError: () => isFileNotFoundError,
|
|
51
|
+
openRegedit: () => openRegedit,
|
|
52
|
+
readJSONFile: () => readJSONFile,
|
|
53
|
+
readOrInitJSON: () => readOrInitJSON,
|
|
54
|
+
showInExplorer: () => showInExplorer,
|
|
55
|
+
updateJSON: () => updateJSON,
|
|
56
|
+
writeJSONFile: () => writeJSONFile
|
|
57
|
+
});
|
|
58
|
+
module.exports = __toCommonJS(node_exports);
|
|
59
|
+
|
|
60
|
+
// src/node/utils/env.ts
|
|
61
|
+
function getEnv() {
|
|
62
|
+
const env = {};
|
|
63
|
+
for (const envKey in process.env) {
|
|
64
|
+
env[envKey] = process.env[envKey];
|
|
65
|
+
}
|
|
66
|
+
return env;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/node/utils/file/base.ts
|
|
70
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
71
|
+
async function isFile(filePath) {
|
|
72
|
+
try {
|
|
73
|
+
return (await import_promises.default.stat(filePath)).isFile();
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function existsFile(file, mode) {
|
|
79
|
+
try {
|
|
80
|
+
import_promises.default.access(file, mode);
|
|
81
|
+
return true;
|
|
82
|
+
} catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function ensureDirSync(dirPath) {
|
|
87
|
+
import_promises.default.mkdir(dirPath, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
async function ensureDir(dirPath) {
|
|
90
|
+
await import_promises.default.mkdir(dirPath, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
function isFileNotFoundError(error) {
|
|
93
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/node/utils/file/delete.ts
|
|
97
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
98
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
99
|
+
async function emptyDirectory(dir) {
|
|
100
|
+
const deletedPaths = [];
|
|
101
|
+
const entries = await import_promises2.default.readdir(dir, { withFileTypes: true });
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
const fullPath = import_node_path.default.join(dir, entry.name);
|
|
104
|
+
if (entry.isDirectory()) {
|
|
105
|
+
deletedPaths.push(...await emptyDirectory(fullPath));
|
|
106
|
+
await import_promises2.default.rmdir(fullPath);
|
|
107
|
+
} else {
|
|
108
|
+
await import_promises2.default.unlink(fullPath);
|
|
109
|
+
}
|
|
110
|
+
deletedPaths.push(fullPath);
|
|
111
|
+
}
|
|
112
|
+
return deletedPaths;
|
|
113
|
+
}
|
|
114
|
+
async function deleteFiles(paths) {
|
|
115
|
+
const results = await Promise.allSettled(
|
|
116
|
+
paths.map(async (file) => {
|
|
117
|
+
await import_promises2.default.unlink(file);
|
|
118
|
+
return file;
|
|
119
|
+
})
|
|
120
|
+
);
|
|
121
|
+
return results.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/node/utils/file/download.ts
|
|
125
|
+
var import_promises3 = require("stream/promises");
|
|
126
|
+
var import_node_fs = require("fs");
|
|
127
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
128
|
+
async function downloadFile(url, filePath) {
|
|
129
|
+
const file = import_node_path2.default.resolve(filePath);
|
|
130
|
+
const res = await fetch(url);
|
|
131
|
+
if (!res.ok || !res.body) {
|
|
132
|
+
throw new Error(`\u4E0B\u8F7D\u5931\u8D25: ${res.status}`);
|
|
133
|
+
}
|
|
134
|
+
await (0, import_promises3.pipeline)(res.body, (0, import_node_fs.createWriteStream)(file));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/node/utils/file/find.ts
|
|
138
|
+
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
139
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
140
|
+
async function findFilesByPrefixAndSuffix(dir, prefix, suffix) {
|
|
141
|
+
return (await import_promises4.default.readdir(dir, { withFileTypes: true })).filter(
|
|
142
|
+
(dirent) => (
|
|
143
|
+
// 仅保留文件(排除子目录)
|
|
144
|
+
dirent.isFile() && // 文件名匹配前缀
|
|
145
|
+
dirent.name.startsWith(prefix || "") && // 文件名匹配后缀
|
|
146
|
+
dirent.name.endsWith(suffix || "")
|
|
147
|
+
)
|
|
148
|
+
).map((dirent) => import_node_path3.default.join(dir, dirent.name));
|
|
149
|
+
}
|
|
150
|
+
async function findFiles(dir, target) {
|
|
151
|
+
const results = [];
|
|
152
|
+
const entries = await import_promises4.default.readdir(dir, { withFileTypes: true });
|
|
153
|
+
for (const entry of entries) {
|
|
154
|
+
const fullPath = import_node_path3.default.join(dir, entry.name);
|
|
155
|
+
if (entry.isDirectory()) {
|
|
156
|
+
results.push(...await findFiles(fullPath, target));
|
|
157
|
+
} else if (typeof target === "string" && entry.name === target) {
|
|
158
|
+
results.push(fullPath);
|
|
159
|
+
} else if (typeof target === "function" && target(entry.name, fullPath)) {
|
|
160
|
+
results.push(fullPath);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return results;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/node/utils/file/json.ts
|
|
167
|
+
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
168
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
169
|
+
async function readJSONFile(filePath) {
|
|
170
|
+
if (!await isFile(filePath)) {
|
|
171
|
+
throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
172
|
+
}
|
|
173
|
+
const jsonRaw = await import_promises5.default.readFile(import_node_path4.default.resolve(filePath), "utf-8");
|
|
174
|
+
return JSON.parse(jsonRaw);
|
|
175
|
+
}
|
|
176
|
+
async function writeJSONFile(file, data) {
|
|
177
|
+
const tempFile = `${file}.tmp.${Date.now()}`;
|
|
178
|
+
const jsonContent = JSON.stringify(data, null, 2);
|
|
179
|
+
await import_promises5.default.writeFile(tempFile, jsonContent, "utf-8");
|
|
180
|
+
await import_promises5.default.rename(tempFile, file);
|
|
181
|
+
}
|
|
182
|
+
async function updateJSON(file, updater) {
|
|
183
|
+
const oldData = await readJSONFile(file);
|
|
184
|
+
const newData = updater(oldData);
|
|
185
|
+
await writeJSONFile(file, newData);
|
|
186
|
+
return newData;
|
|
187
|
+
}
|
|
188
|
+
async function readOrInitJSON(file, initData) {
|
|
189
|
+
try {
|
|
190
|
+
const content = await import_promises5.default.readFile(file, "utf-8");
|
|
191
|
+
return JSON.parse(content);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
if (!isFileNotFoundError(error)) {
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
const data = await initData();
|
|
197
|
+
await ensureDir(import_node_path4.default.dirname(file));
|
|
198
|
+
await import_promises5.default.writeFile(file, JSON.stringify(data, null, 2), "utf-8");
|
|
199
|
+
return data;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/core/utils/number/format.ts
|
|
204
|
+
function formatUnitSize(value, base, units, invalidText = "") {
|
|
205
|
+
if (!Number.isFinite(value)) {
|
|
206
|
+
return { size: 0, unit: "", text: invalidText };
|
|
207
|
+
}
|
|
208
|
+
let size = value;
|
|
209
|
+
let unitIndex = 0;
|
|
210
|
+
while (size >= base && unitIndex < units.length - 1) {
|
|
211
|
+
size /= base;
|
|
212
|
+
unitIndex++;
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
size,
|
|
216
|
+
unit: units[unitIndex],
|
|
217
|
+
text: `${size.toFixed(2).replace(/\.?0+$/, "")} ${units[unitIndex]}`
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/node/utils/file/size.ts
|
|
222
|
+
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
223
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
224
|
+
function formatFileSizeFromKB(sizeKB, invalidText = "") {
|
|
225
|
+
const { size, unit, text } = formatUnitSize(sizeKB, 1024, ["KB", "MB", "GB"], invalidText);
|
|
226
|
+
if (text === invalidText) {
|
|
227
|
+
return invalidText;
|
|
228
|
+
}
|
|
229
|
+
const integerPart = Math.floor(size);
|
|
230
|
+
let fractionDigits;
|
|
231
|
+
if (integerPart > 99) fractionDigits = 0;
|
|
232
|
+
else if (integerPart > 9) fractionDigits = 1;
|
|
233
|
+
else fractionDigits = 2;
|
|
234
|
+
const rounded = Math.round(size * 10 ** fractionDigits) / 10 ** fractionDigits;
|
|
235
|
+
return `${rounded} ${unit}`;
|
|
236
|
+
}
|
|
237
|
+
async function getFileSize(filePath) {
|
|
238
|
+
try {
|
|
239
|
+
const stat2 = await import_promises6.default.stat(filePath);
|
|
240
|
+
return stat2.size;
|
|
241
|
+
} catch {
|
|
242
|
+
return 0;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function getSymbolicLinkSize(linkPath) {
|
|
246
|
+
try {
|
|
247
|
+
const stat2 = await import_promises6.default.lstat(linkPath);
|
|
248
|
+
return stat2.size;
|
|
249
|
+
} catch {
|
|
250
|
+
return 0;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async function getDirSize(dir) {
|
|
254
|
+
let entries;
|
|
255
|
+
try {
|
|
256
|
+
entries = await import_promises6.default.readdir(dir, { withFileTypes: true });
|
|
257
|
+
} catch {
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
const tasks = [];
|
|
261
|
+
for (const entry of entries) {
|
|
262
|
+
const fullPath = import_node_path5.default.join(dir, entry.name);
|
|
263
|
+
if (entry.isDirectory()) {
|
|
264
|
+
tasks.push(getDirSize(fullPath));
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (entry.isSymbolicLink()) {
|
|
268
|
+
tasks.push(getSymbolicLinkSize(fullPath));
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
tasks.push(getFileSize(fullPath));
|
|
272
|
+
}
|
|
273
|
+
const results = await Promise.allSettled(tasks);
|
|
274
|
+
return results.reduce((total, result) => {
|
|
275
|
+
return total + (result.status === "fulfilled" ? result.value : 0);
|
|
276
|
+
}, 0);
|
|
277
|
+
}
|
|
278
|
+
async function getFileSizeKB(filePath) {
|
|
279
|
+
try {
|
|
280
|
+
const stat2 = await import_promises6.default.stat(filePath);
|
|
281
|
+
if (stat2.isDirectory()) {
|
|
282
|
+
return await getDirSize(filePath) / 1024;
|
|
283
|
+
} else {
|
|
284
|
+
return stat2.size / 1024;
|
|
285
|
+
}
|
|
286
|
+
} catch {
|
|
287
|
+
return 0;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/core/utils/error.ts
|
|
292
|
+
function createAbortError(msg) {
|
|
293
|
+
const error = new Error(msg ?? "\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
294
|
+
error.name = "AbortError";
|
|
295
|
+
return error;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/node/utils/win/cmd.ts
|
|
299
|
+
var import_node_child_process = require("child_process");
|
|
300
|
+
var iconv = __toESM(require("iconv-lite"), 1);
|
|
301
|
+
async function execWinCmd(cmd, options) {
|
|
302
|
+
return new Promise((resolve, reject) => {
|
|
303
|
+
if (options?.signal?.aborted) {
|
|
304
|
+
throw createAbortError();
|
|
305
|
+
}
|
|
306
|
+
let abortHandler = null;
|
|
307
|
+
const child = (0, import_node_child_process.exec)(`${cmd}`, { encoding: "buffer" }, (error, stdout, stderr) => {
|
|
308
|
+
const stdoutStr = iconv.decode(stdout, "cp936");
|
|
309
|
+
const stderrStr = iconv.decode(stderr, "cp936");
|
|
310
|
+
if (abortHandler) {
|
|
311
|
+
options?.signal?.removeEventListener("abort", abortHandler);
|
|
312
|
+
}
|
|
313
|
+
const exitCode = error ? Number(error.code ?? 0) : 0;
|
|
314
|
+
if (options?.codeIsSuccess ? !options.codeIsSuccess(exitCode) : exitCode !== 0) {
|
|
315
|
+
reject(new Error(`\u547D\u4EE4\u884C\u6267\u884C\u51FA\u9519 (${exitCode}): ${stderrStr || stdoutStr}`));
|
|
316
|
+
} else {
|
|
317
|
+
resolve(stdoutStr);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
let timeout;
|
|
321
|
+
abortHandler = () => {
|
|
322
|
+
child.kill("SIGTERM");
|
|
323
|
+
timeout = setTimeout(() => {
|
|
324
|
+
child.kill("SIGKILL");
|
|
325
|
+
}, 3e3);
|
|
326
|
+
reject(createAbortError());
|
|
327
|
+
};
|
|
328
|
+
if (options?.signal) {
|
|
329
|
+
options.signal.addEventListener("abort", abortHandler);
|
|
330
|
+
}
|
|
331
|
+
child.on("close", () => {
|
|
332
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
333
|
+
options?.signal?.removeEventListener("abort", abortHandler);
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// src/node/utils/win/copy.ts
|
|
339
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
340
|
+
async function copyFile(source, destination, signal) {
|
|
341
|
+
const src = import_node_path6.default.resolve(source);
|
|
342
|
+
const dest = import_node_path6.default.resolve(destination);
|
|
343
|
+
let command;
|
|
344
|
+
if (await isFile(source)) {
|
|
345
|
+
command = `copy "${src}" "${dest}"`;
|
|
346
|
+
await execWinCmd(command, { signal });
|
|
347
|
+
} else {
|
|
348
|
+
command = `robocopy "${src}" "${dest}" /E /NFL /NDL /NJH /NJS /NC /NS /NP`;
|
|
349
|
+
await execWinCmd(command, {
|
|
350
|
+
codeIsSuccess: (number) => number < 8,
|
|
351
|
+
signal
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// src/node/utils/win/explorer.ts
|
|
357
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
358
|
+
var fs6 = __toESM(require("fs/promises"), 1);
|
|
359
|
+
async function showInExplorer(fileOrDir) {
|
|
360
|
+
fileOrDir = import_node_path7.default.resolve(fileOrDir);
|
|
361
|
+
if ((await fs6.stat(fileOrDir)).isDirectory()) {
|
|
362
|
+
await execWinCmd(`start "" "${fileOrDir}"`);
|
|
363
|
+
} else {
|
|
364
|
+
await execWinCmd(`start "" explorer /select,"${fileOrDir}"`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/node/utils/win/regedit.ts
|
|
369
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
370
|
+
async function openRegedit(path9) {
|
|
371
|
+
return execWinCmd(
|
|
372
|
+
`taskkill /f /im regedit.exe & REG ADD "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit" /v "LastKey" /d "${path9}" /f & regedit`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
async function exportRegedit(regPath, filePath) {
|
|
376
|
+
filePath = import_node_path8.default.resolve(filePath);
|
|
377
|
+
await ensureDir(regPath);
|
|
378
|
+
await execWinCmd(`reg export "${regPath}" "${filePath}" /y`, void 0);
|
|
379
|
+
}
|
|
380
|
+
async function importRegedit(regPath, filePath) {
|
|
381
|
+
await execWinCmd(`reg import "${import_node_path8.default.resolve(filePath)}"`, void 0);
|
|
382
|
+
}
|
|
383
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
384
|
+
0 && (module.exports = {
|
|
385
|
+
copyFile,
|
|
386
|
+
deleteFiles,
|
|
387
|
+
downloadFile,
|
|
388
|
+
emptyDirectory,
|
|
389
|
+
ensureDir,
|
|
390
|
+
ensureDirSync,
|
|
391
|
+
execWinCmd,
|
|
392
|
+
existsFile,
|
|
393
|
+
exportRegedit,
|
|
394
|
+
findFiles,
|
|
395
|
+
findFilesByPrefixAndSuffix,
|
|
396
|
+
formatFileSizeFromKB,
|
|
397
|
+
getDirSize,
|
|
398
|
+
getEnv,
|
|
399
|
+
getFileSizeKB,
|
|
400
|
+
importRegedit,
|
|
401
|
+
isFile,
|
|
402
|
+
isFileNotFoundError,
|
|
403
|
+
openRegedit,
|
|
404
|
+
readJSONFile,
|
|
405
|
+
readOrInitJSON,
|
|
406
|
+
showInExplorer,
|
|
407
|
+
updateJSON,
|
|
408
|
+
writeJSONFile
|
|
409
|
+
});
|
|
410
|
+
//# sourceMappingURL=node.cjs.map
|