@zwa73/utils 1.0.223 → 1.0.224

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/{UtilClass → cjs/UtilClass}/Hbs.js +13 -6
  2. package/dist/{UtilClass → cjs/UtilClass}/index.js +0 -1
  3. package/dist/{UtilCodecs.js → cjs/UtilCodecs.js} +24 -16
  4. package/dist/{UtilDecorators.js → cjs/UtilDecorators.js} +0 -1
  5. package/dist/{UtilFileTools.js → cjs/UtilFileTools.js} +10 -4
  6. package/dist/{UtilFunctions.js → cjs/UtilFunctions.js} +10 -5
  7. package/dist/{UtilSymbol.js → cjs/UtilSymbol.js} +0 -1
  8. package/dist/mjs/QuickExport.mjs +35 -0
  9. package/dist/mjs/UtilClass/Hbs.mjs +51 -0
  10. package/dist/mjs/UtilClass/index.mjs +3 -0
  11. package/dist/mjs/UtilCodecs.mjs +109 -0
  12. package/dist/mjs/UtilDecorators.mjs +2 -0
  13. package/dist/mjs/UtilFP.mjs +2 -0
  14. package/dist/mjs/UtilFileTools.mjs +407 -0
  15. package/dist/mjs/UtilFunctions.mjs +138 -0
  16. package/dist/mjs/UtilHttp.mjs +475 -0
  17. package/dist/mjs/UtilI18n.mjs +206 -0
  18. package/dist/mjs/UtilInterfaces.mjs +2 -0
  19. package/dist/mjs/UtilLogger.mjs +361 -0
  20. package/dist/mjs/UtilSymbol.mjs +2 -0
  21. package/dist/mjs/index.mjs +17 -0
  22. package/dist/{UtilClass → types/UtilClass}/Hbs.d.ts +6 -3
  23. package/dist/types/UtilClass/index.d.ts +3 -0
  24. package/dist/{UtilCodecs.d.ts → types/UtilCodecs.d.ts} +6 -6
  25. package/dist/types/UtilDecorators.d.ts +2 -0
  26. package/dist/{UtilFileTools.d.ts → types/UtilFileTools.d.ts} +11 -3
  27. package/dist/{UtilFunctions.d.ts → types/UtilFunctions.d.ts} +3 -3
  28. package/dist/types/UtilInterfaces.d.ts +1 -0
  29. package/dist/types/UtilSymbol.d.ts +2 -0
  30. package/package.json +8 -2
  31. package/dist/UtilClass/index.d.ts +0 -2
  32. package/dist/UtilDecorators.d.ts +0 -1
  33. package/dist/UtilInterfaces.d.ts +0 -1
  34. package/dist/UtilSymbol.d.ts +0 -1
  35. /package/dist/{QuickExport.js → cjs/QuickExport.js} +0 -0
  36. /package/dist/{UtilFP.js → cjs/UtilFP.js} +0 -0
  37. /package/dist/{UtilHttp.js → cjs/UtilHttp.js} +0 -0
  38. /package/dist/{UtilI18n.js → cjs/UtilI18n.js} +0 -0
  39. /package/dist/{UtilInterfaces.js → cjs/UtilInterfaces.js} +0 -0
  40. /package/dist/{UtilLogger.js → cjs/UtilLogger.js} +0 -0
  41. /package/dist/{index.js → cjs/index.js} +0 -0
  42. /package/dist/{QuickExport.d.ts → types/QuickExport.d.ts} +0 -0
  43. /package/dist/{UtilFP.d.ts → types/UtilFP.d.ts} +0 -0
  44. /package/dist/{UtilHttp.d.ts → types/UtilHttp.d.ts} +0 -0
  45. /package/dist/{UtilI18n.d.ts → types/UtilI18n.d.ts} +0 -0
  46. /package/dist/{UtilLogger.d.ts → types/UtilLogger.d.ts} +0 -0
  47. /package/dist/{index.d.ts → types/index.d.ts} +0 -0
@@ -0,0 +1,407 @@
1
+ import * as fs from "fs";
2
+ import path from 'pathe';
3
+ import * as os from "os";
4
+ import { SLogger } from "./UtilLogger.mjs";
5
+ import * as JSON5 from 'json5';
6
+ import { globSync, glob } from "glob";
7
+ import { UtilFunc } from "./UtilFunctions.mjs";
8
+ import crypto from 'crypto';
9
+ /**文件工具 */
10
+ export var UtilFT;
11
+ (function (UtilFT) {
12
+ /**验证路径 文件或文件夹 是否存在 异步
13
+ * @async
14
+ * @param filePath - 待验证的路径
15
+ * @returns 是否存在
16
+ */
17
+ async function pathExists(filePath) {
18
+ try {
19
+ await fs.promises.access(filePath);
20
+ return true;
21
+ }
22
+ catch (e) {
23
+ return false;
24
+ }
25
+ }
26
+ UtilFT.pathExists = pathExists;
27
+ /**验证路径 文件或文件夹 是否存在 同步
28
+ * @param filePath - 待验证的路径
29
+ * @returns - 是否存在
30
+ */
31
+ function pathExistsSync(filePath) {
32
+ try {
33
+ fs.accessSync(filePath);
34
+ return true;
35
+ }
36
+ catch (e) {
37
+ return false;
38
+ }
39
+ }
40
+ UtilFT.pathExistsSync = pathExistsSync;
41
+ /**路径不存在时创建路径 以path.sep结尾时创建文件夹 异步
42
+ * @async
43
+ * @param filePath - 待创建的路径
44
+ * @param opt - 可选参数
45
+ * @param opt.dir - 创建一个目录
46
+ * @returns 是否成功创建
47
+ */
48
+ async function createPath(filePath, opt) {
49
+ if (opt?.dir == true)
50
+ filePath = path.join(filePath, path.sep);
51
+ try {
52
+ if (filePath.endsWith(path.sep)) {
53
+ await fs.promises.mkdir(filePath, { recursive: true });
54
+ return true;
55
+ }
56
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
57
+ const filehandle = await fs.promises.open(filePath, 'w');
58
+ await filehandle.close();
59
+ return true;
60
+ }
61
+ catch (e) {
62
+ SLogger.error("createPath 错误", e);
63
+ return false;
64
+ }
65
+ }
66
+ UtilFT.createPath = createPath;
67
+ /**路径不存在时创建路径 以path.sep结尾时创建文件夹 同步
68
+ * @param filePath - 待创建的路径
69
+ * @param opt - 可选参数
70
+ * @param opt.dir - 创建一个目录
71
+ * @returns 是否成功创建
72
+ */
73
+ function createPathSync(filePath, opt) {
74
+ if (opt?.dir == true)
75
+ filePath = path.join(filePath, path.sep);
76
+ try {
77
+ if (filePath.endsWith(path.sep)) {
78
+ fs.mkdirSync(filePath, { recursive: true });
79
+ return true;
80
+ }
81
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
82
+ fs.openSync(filePath, 'w');
83
+ return true;
84
+ }
85
+ catch (e) {
86
+ SLogger.error("createPathSync 错误", e);
87
+ return false;
88
+ }
89
+ }
90
+ UtilFT.createPathSync = createPathSync;
91
+ /**确保路径存在 不存在时创建 异步
92
+ * @async
93
+ * @param filePath - 待验证的路径
94
+ * @param opt - 可选参数
95
+ * @param opt.dir - 强制验证一个文件夹
96
+ * @returns 是否成功执行 创建或已存在
97
+ */
98
+ async function ensurePathExists(filePath, opt) {
99
+ if (await pathExists(filePath))
100
+ return true;
101
+ return await createPath(filePath, opt);
102
+ }
103
+ UtilFT.ensurePathExists = ensurePathExists;
104
+ /**确保路径存在 不存在时创建 同步
105
+ * @param filePath - 待验证的路径
106
+ * @param opt - 可选参数
107
+ * @param opt.dir - 强制验证一个文件夹
108
+ * @returns 是否成功执行 创建或已存在
109
+ */
110
+ function ensurePathExistsSync(filePath, opt) {
111
+ if (pathExistsSync(filePath))
112
+ return true;
113
+ return createPathSync(filePath, opt);
114
+ }
115
+ UtilFT.ensurePathExistsSync = ensurePathExistsSync;
116
+ function loadJSONFileSync(filePath, opt) {
117
+ try {
118
+ if (opt?.forceExt !== true && path.extname(filePath) !== '.json')
119
+ filePath += '.json';
120
+ const str = pathExistsSync(filePath)
121
+ ? fs.readFileSync(filePath, "utf-8")
122
+ : "";
123
+ // 如果不存在则返回默认值
124
+ if (str == "" || str == null) {
125
+ if (opt?.default !== undefined)
126
+ return opt.default;
127
+ return {};
128
+ }
129
+ if (opt?.json5)
130
+ return JSON5.parse(str);
131
+ return JSON.parse(str);
132
+ }
133
+ catch (e) {
134
+ SLogger.error(`loadJSONFileSync 错误 filePath:${filePath}`);
135
+ throw e;
136
+ }
137
+ }
138
+ UtilFT.loadJSONFileSync = loadJSONFileSync;
139
+ async function loadJSONFile(filePath, opt) {
140
+ try {
141
+ if (opt?.forceExt !== true && path.extname(filePath) !== '.json')
142
+ filePath += '.json';
143
+ const str = (await pathExists(filePath))
144
+ ? await fs.promises.readFile(filePath, "utf-8")
145
+ : "";
146
+ // 如果不存在则返回默认值
147
+ if (str == "" || str == null) {
148
+ if (opt?.default !== undefined)
149
+ return opt.default;
150
+ return {};
151
+ }
152
+ if (opt?.json5)
153
+ return JSON5.parse(str);
154
+ return JSON.parse(str);
155
+ }
156
+ catch (e) {
157
+ SLogger.error(`loadJSONFile 错误 filePath:${filePath}`);
158
+ throw e;
159
+ }
160
+ }
161
+ UtilFT.loadJSONFile = loadJSONFile;
162
+ /**写入JSON文件
163
+ * @async
164
+ * @param filePath - 文件路径
165
+ * @param token - 所要写入的JToken
166
+ * @param opt - 可选参数
167
+ * @param opt.compress - 使用紧凑风格 将会用/\uF121\uF122\uF123.+\uF121\uF122\uF123/作为特殊标记, 原始文本内若出现相同格式将会产生错误
168
+ * @param opt.forceExt - 不自动修改扩展名为json
169
+ * @param opt.compressThreshold - 紧凑风格 压缩阈值 默认100
170
+ */
171
+ async function writeJSONFile(filePath, token, opt) {
172
+ const str = UtilFunc.stringifyJToken(token, opt);
173
+ if (opt?.forceExt !== true && path.extname(filePath) !== '.json')
174
+ filePath += '.json';
175
+ // 判断文件路径是否存在 不存在则创建
176
+ if (!(await pathExists(filePath)))
177
+ await createPath(filePath);
178
+ // 写入文件
179
+ try {
180
+ await fs.promises.writeFile(filePath, str);
181
+ SLogger.verbose(`${filePath} writeJSONFile 成功`);
182
+ }
183
+ catch (err) {
184
+ SLogger.error(`${filePath} writeJSONFile 错误`, err);
185
+ }
186
+ }
187
+ UtilFT.writeJSONFile = writeJSONFile;
188
+ /**保证路径为某个风格
189
+ * @param filePath - 输入路径
190
+ * @param style - 目标风格 undefined 时不改变
191
+ * @returns 新的符合目标风格的路径
192
+ */
193
+ function stylizePath(filePath, style) {
194
+ if (style === undefined)
195
+ return filePath;
196
+ return UtilFunc.match(style, {
197
+ posix: (nor) => filePath.replaceAll("\\", "/"),
198
+ win32: (nor) => filePath.replaceAll("/", "\\"),
199
+ });
200
+ }
201
+ UtilFT.stylizePath = stylizePath;
202
+ /**保证路径为POSIX风格
203
+ * @param filePath - 输入路径
204
+ * @returns 新的符合POSIX风格的路径
205
+ */
206
+ function posixizePath(filePath) {
207
+ return stylizePath(filePath, 'posix');
208
+ }
209
+ UtilFT.posixizePath = posixizePath;
210
+ /**保证路径为Win32风格
211
+ * @param filePath - 输入路径
212
+ * @returns 新的符合Win32风格的路径
213
+ */
214
+ function win32izePath(filePath) {
215
+ return stylizePath(filePath, 'win32');
216
+ }
217
+ UtilFT.win32izePath = win32izePath;
218
+ /**保证路径为当前系统风格
219
+ * @param filePath - 输入路径
220
+ * @returns 新的符合当前系统风格的路径
221
+ */
222
+ function currosizePath(filePath) {
223
+ const system = os.platform();
224
+ if (system === 'win32')
225
+ return win32izePath(filePath);
226
+ return posixizePath(filePath);
227
+ }
228
+ UtilFT.currosizePath = currosizePath;
229
+ /**逐级寻找node_modules文件夹
230
+ * @param basePath - 基础位置
231
+ * @param extpaths - 额外的路径 如 .bin
232
+ * @returns node_modules文件夹路径 包含额外路径
233
+ */
234
+ async function findNodeModulesDir(basePath, ...extpaths) {
235
+ let currentDir = basePath;
236
+ while (currentDir) {
237
+ const nodeModulesPath = path.join(currentDir, 'node_modules', ...extpaths);
238
+ if (await UtilFT.pathExists(nodeModulesPath))
239
+ return nodeModulesPath;
240
+ const parentDir = path.dirname(currentDir);
241
+ if (parentDir === currentDir)
242
+ break;
243
+ currentDir = parentDir;
244
+ }
245
+ return undefined;
246
+ }
247
+ UtilFT.findNodeModulesDir = findNodeModulesDir;
248
+ /**搜索路径符合正则表达式的文件
249
+ * @param dir - 起始目录
250
+ * @param traitRegex - 正则表达式
251
+ * @param opt - 可选参数
252
+ * @param opt.recursive - 搜索子目录
253
+ * @returns 文件名路径数组
254
+ */
255
+ async function fileSearchRegex(dir, traitRegex, opt) {
256
+ const fixopt = Object.assign({ recursive: true, nodir: true }, opt);
257
+ //如果使用 g 会导致 RegExp.lastIndex 更改, 将会导致匹配错误
258
+ const regex = new RegExp(traitRegex);
259
+ const recursive = async (curPath) => {
260
+ const subDir = path.join(dir, curPath);
261
+ const subFiles = await fs.promises.readdir(subDir, { withFileTypes: true });
262
+ const matchFiles = await Promise.all(subFiles.map(async (subFile) => {
263
+ const subFilePath = path.join(subDir, subFile.name);
264
+ const nextPath = path.join(curPath, subFile.name);
265
+ //判断是否是文件夹,递归调用
266
+ if (subFile.isDirectory() && fixopt.recursive) {
267
+ if (fixopt.nodir)
268
+ return recursive(nextPath);
269
+ return [nextPath, ...await recursive(nextPath)];
270
+ }
271
+ if (regex.test(nextPath))
272
+ return [subFilePath];
273
+ return [undefined];
274
+ }));
275
+ return matchFiles.flat()
276
+ .filter(v => v != undefined)
277
+ .map(fp => path.normalize(fp));
278
+ };
279
+ return recursive('');
280
+ }
281
+ UtilFT.fileSearchRegex = fileSearchRegex;
282
+ /**搜索路径符合正则表达式的文件 同步版本
283
+ * @param dir - 起始目录
284
+ * @param traitRegex - 正则表达式
285
+ * @param opt - 可选参数
286
+ * @param opt.relative - 搜索子目录
287
+ * @returns 文件名路径数组
288
+ */
289
+ function fileSearchRegexSync(dir, traitRegex, opt) {
290
+ const fixopt = Object.assign({ recursive: true, nodir: true }, opt);
291
+ //如果使用 g 会导致 RegExp.lastIndex 更改, 将会导致匹配错误
292
+ const regex = new RegExp(traitRegex);
293
+ const recursive = (curPath) => {
294
+ const subDir = path.join(dir, curPath);
295
+ const subFiles = fs.readdirSync(subDir, { withFileTypes: true });
296
+ const matchFiles = subFiles.map(subFile => {
297
+ const subFilePath = path.join(subDir, subFile.name);
298
+ const nextPath = path.join(curPath, subFile.name);
299
+ //判断是否是文件夹,递归调用
300
+ if (subFile.isDirectory() && fixopt.recursive) {
301
+ if (fixopt.nodir)
302
+ return recursive(nextPath);
303
+ return [nextPath, ...recursive(nextPath)];
304
+ }
305
+ if (regex.test(nextPath))
306
+ return [subFilePath];
307
+ return [undefined];
308
+ });
309
+ return matchFiles.flat()
310
+ .filter(v => v != undefined)
311
+ .map(fp => path.normalize(fp));
312
+ };
313
+ return recursive('');
314
+ }
315
+ UtilFT.fileSearchRegexSync = fileSearchRegexSync;
316
+ /**搜索符合Glob匹配的文件
317
+ * @param dir - 起始目录
318
+ * @param globPattern - glob匹配
319
+ * @param opt - 可选参数
320
+ * @param opt.ignore - 忽略的文件
321
+ * @param opt.relative - 忽略目录 默认 true
322
+ * @param opt.nodir - 忽略大小写 默认 跟随系统 mac/win为true 其他false
323
+ * @returns 文件绝对路径数组
324
+ */
325
+ async function fileSearchGlob(dir, globPattern, opt) {
326
+ const fixedPath = typeof globPattern === "string"
327
+ ? path.join(dir, globPattern)
328
+ : globPattern.map(p => path.join(dir, p));
329
+ return (await glob(fixedPath, { absolute: true, ...(opt ?? {}) }))
330
+ .map(filePath => path.normalize(filePath));
331
+ }
332
+ UtilFT.fileSearchGlob = fileSearchGlob;
333
+ /**搜索符合Glob匹配的文件 同步版本
334
+ * @param dir - 起始目录
335
+ * @param globPattern - glob匹配
336
+ * @param opt - 可选参数
337
+ * @param opt.ignore - 忽略的文件
338
+ * @param opt.relative - 忽略目录 默认 true
339
+ * @param opt.nodir - 忽略大小写 默认 跟随系统 mac/win为true 其他false
340
+ * @returns 文件绝对路径数组
341
+ */
342
+ function fileSearchGlobSync(dir, globPattern, opt) {
343
+ const fixedPath = typeof globPattern === "string"
344
+ ? path.join(dir, globPattern)
345
+ : globPattern.map(p => path.join(dir, p));
346
+ return globSync(fixedPath, { absolute: true, ...(opt ?? {}) })
347
+ .map(filePath => path.normalize(filePath));
348
+ }
349
+ UtilFT.fileSearchGlobSync = fileSearchGlobSync;
350
+ /**是一个有效的文件路径
351
+ * @param filePath - 需要验证的文件路径
352
+ */
353
+ function isValidFilePath(filePath) {
354
+ if (filePath.length > 255)
355
+ return false;
356
+ const invalidCharacters = ['<', '>', '"', '|', '?', '*'];
357
+ for (const invalidCharacter of invalidCharacters) {
358
+ if (filePath.includes(invalidCharacter))
359
+ return false;
360
+ }
361
+ return true;
362
+ }
363
+ UtilFT.isValidFilePath = isValidFilePath;
364
+ /**计算文件的部分md5
365
+ * @param filePath - 目标文件路径
366
+ * @param opt - 可选参数
367
+ * @param opt.algorithm - hash算法 默认md5
368
+ * @param opt.sampled - 抽取部分计算 默认false
369
+ * @param opt.chunkSize - 抽取的块大小 默认1024
370
+ * @param opt.chunkCount - 抽取的块的数量 默认10
371
+ */
372
+ async function calculateHash(filePath, opt) {
373
+ const { algorithm = "md5", chunkSize = 1024, chunkCount = 10, sampled = false } = opt ?? {};
374
+ const chash = async (filePath) => new Promise((resolve, reject) => {
375
+ const hash = crypto.createHash(algorithm);
376
+ const stream = fs.createReadStream(filePath);
377
+ stream.on("data", (data) => hash.update(data));
378
+ stream.on("end", () => resolve(hash.digest("hex")));
379
+ stream.on("error", reject);
380
+ });
381
+ if (!sampled)
382
+ return chash(filePath);
383
+ const stats = await fs.promises.stat(filePath);
384
+ const totalSize = stats.size;
385
+ //抽取量大于文件大小则直接计算完整hash
386
+ if (totalSize < chunkSize * chunkCount)
387
+ return chash(filePath);
388
+ const poslist = Array.from({ length: chunkCount }, (_, i) => Math.floor((totalSize / chunkCount) * i));
389
+ const hash = crypto.createHash(algorithm);
390
+ for (const pos of poslist) {
391
+ const buffer = await new Promise((resolve, reject) => {
392
+ const stream = fs.createReadStream(filePath, {
393
+ start: pos,
394
+ end: Math.min(pos + chunkSize - 1, totalSize - 1),
395
+ highWaterMark: chunkSize,
396
+ });
397
+ const chunks = [];
398
+ stream.on("data", (chunk) => chunks.push(chunk));
399
+ stream.on("end", () => resolve(Buffer.concat(chunks)));
400
+ stream.on("error", reject);
401
+ });
402
+ hash.update(buffer);
403
+ }
404
+ return hash.digest("hex");
405
+ }
406
+ UtilFT.calculateHash = calculateHash;
407
+ })(UtilFT || (UtilFT = {}));
@@ -0,0 +1,138 @@
1
+ import * as crypto from "crypto";
2
+ import * as cp from "child_process";
3
+ import { None } from "./UtilSymbol.mjs";
4
+ import opath from 'path';
5
+ import { UtilFT } from "./UtilFileTools.mjs";
6
+ import { SLogger } from "./UtilLogger.mjs";
7
+ import { JsFunc } from "@zwa73/js-utils";
8
+ import { composeClassPart } from "@zwa73/modular-mixer";
9
+ const HashAlgorithmList = [
10
+ 'RSA-MD5', 'RSA-RIPEMD160', 'RSA-SHA1', 'RSA-SHA1-2', 'RSA-SHA224',
11
+ 'RSA-SHA256', 'RSA-SHA3-224', 'RSA-SHA3-256', 'RSA-SHA3-384', 'RSA-SHA3-512',
12
+ 'RSA-SHA384', 'RSA-SHA512', 'RSA-SHA512/224', 'RSA-SHA512/256', 'RSA-SM3',
13
+ 'blake2b512', 'blake2s256', 'id-rsassa-pkcs1-v1_5-with-sha3-224',
14
+ 'id-rsassa-pkcs1-v1_5-with-sha3-256', 'id-rsassa-pkcs1-v1_5-with-sha3-384',
15
+ 'id-rsassa-pkcs1-v1_5-with-sha3-512', 'md5', 'md5-sha1',
16
+ 'md5WithRSAEncryption', 'ripemd', 'ripemd160', 'ripemd160WithRSA', 'rmd160',
17
+ 'sha1', 'sha1WithRSAEncryption', 'sha224', 'sha224WithRSAEncryption',
18
+ 'sha256', 'sha256WithRSAEncryption', 'sha3-224', 'sha3-256', 'sha3-384',
19
+ 'sha3-512', 'sha384', 'sha384WithRSAEncryption', 'sha512', 'sha512-224',
20
+ 'sha512-224WithRSAEncryption', 'sha512-256', 'sha512-256WithRSAEncryption',
21
+ 'sha512WithRSAEncryption', 'shake128', 'shake256', 'sm3',
22
+ 'sm3WithRSAEncryption', 'ssl3-md5', 'ssl3-sha1'
23
+ ];
24
+ /**常用函数 */
25
+ class _UtilFunc {
26
+ /**计算Hash
27
+ * @param str - 待计算的字符串
28
+ * @param method - hash算法
29
+ * @returns hash
30
+ */
31
+ static calcHash(str, opt) {
32
+ const { algorithm = "md5" } = opt ?? {};
33
+ return crypto.createHash(algorithm).update(str).digest('hex');
34
+ }
35
+ /**是否需要检查环境 */
36
+ static checkEnv = true;
37
+ /**是否有正在运行的exec */
38
+ static originalExecTitle = None;
39
+ /**封装的 cp.spawn 执行一段指令,指令运行时实时返回输出
40
+ * @param command - 指令文本
41
+ * @param opt - 可选参数
42
+ * @param opt.outlvl - 普通输出的日志等级
43
+ * @param opt.errlvl - 错误的日志等级
44
+ * @param opt.nodeModules - nodeModules文件夹路径
45
+ * @param opt.cwd - 执行目录
46
+ */
47
+ static async exec(command, opt) {
48
+ return new Promise(async (resolve, reject) => {
49
+ // 创建一个新的环境变量对象,并将项目的 node_modules/.bin 目录添加到 PATH 环境变量中
50
+ const env = Object.create(process.env);
51
+ const penv = opt?.nodeModules
52
+ ? opath.join(UtilFT.currosizePath(opt.nodeModules), '.bin')
53
+ : UtilFT.currosizePath(await UtilFunc.memoize(UtilFT.findNodeModulesDir)(process.cwd(), '.bin') ?? '');
54
+ if (_UtilFunc.checkEnv && (penv == "" || !await UtilFT.pathExists(penv))) {
55
+ SLogger.warn(`UtilFunc.exec 错误, 没有检测到 node_modules/.bin 环境 penv:${penv}`);
56
+ _UtilFunc.checkEnv = false;
57
+ }
58
+ env.PATH = penv + opath.delimiter + env.PATH;
59
+ // 保存原来的标题
60
+ _UtilFunc.originalExecTitle = _UtilFunc.originalExecTitle == None
61
+ ? process.title
62
+ : _UtilFunc.originalExecTitle;
63
+ const cwd = opt?.cwd ?? process.cwd();
64
+ const child = cp.spawn(command, { shell: true, env, cwd });
65
+ let stdout = '';
66
+ let stderr = '';
67
+ child.stdout.on('data', (data) => {
68
+ stdout += data;
69
+ if (opt?.outlvl)
70
+ SLogger.log(opt?.outlvl, data.toString());
71
+ });
72
+ child.stderr.on('data', (data) => {
73
+ stderr += data;
74
+ if (opt?.errlvl)
75
+ SLogger.log(opt?.errlvl, data.toString());
76
+ });
77
+ child.on('error', reject);
78
+ child.on('close', (code) => {
79
+ if (_UtilFunc.originalExecTitle != None) {
80
+ process.title = _UtilFunc.originalExecTitle;
81
+ _UtilFunc.originalExecTitle = None;
82
+ }
83
+ if (code !== 0)
84
+ SLogger.warn(`UtilFunc.exec 命令:"${command}" 结束 代码为:${code}`);
85
+ resolve({ stdout, stderr });
86
+ });
87
+ });
88
+ }
89
+ static publicIp;
90
+ /**获取当前公网ipv4 */
91
+ static async getPublicIpv4() {
92
+ if (_UtilFunc.publicIp === undefined)
93
+ _UtilFunc.publicIp = await _UtilFunc.dynamicImport('public-ip');
94
+ //if(_UtilFunc.publicIp===undefined)
95
+ // _UtilFunc.publicIp = await import("public-ip");
96
+ return _UtilFunc.publicIp.publicIpv4();
97
+ }
98
+ /**动态导入模块的函数。这个函数是为了在TypeScript的模块系统配置为CommonJS时,防止动态import被转译为require而设计的。
99
+ * 使用这个函数,你可以在TypeScript中动态地导入模块,而不需要担心import()被转译为require()。
100
+ * 请注意,这个函数使用了eval(),可能会带来安全风险。
101
+ *
102
+ * @param moduleName - 需要导入的模块的名称。
103
+ * @returns 返回一个Promise。当模块被成功导入时,这个Promise会解析为导入的模块。如果导入失败,这个Promise会被拒绝。
104
+ *
105
+ * @example
106
+ * async function main() {
107
+ * const pip = (await dynamicImport('public-ip')).default;
108
+ * console.log(await pip.v4());
109
+ * }
110
+ * main();
111
+ *
112
+ * @since Node.js 13.2,Node.js开始支持动态import。
113
+ */
114
+ static async dynamicImport(moduleName) {
115
+ const mod = await eval(`import('${moduleName}')`);
116
+ if ('default' in mod)
117
+ return mod.default;
118
+ return mod;
119
+ }
120
+ }
121
+ const key = '__jsUtils';
122
+ const fields = Object.getOwnPropertyNames(JsFunc).filter(k => !['length', 'prototype', 'name'].includes(k));
123
+ export const UtilFunc = composeClassPart({
124
+ base: _UtilFunc,
125
+ mixin: JsFunc,
126
+ key, fields
127
+ });
128
+ //void (async ()=>{
129
+ // const p1 = UtilFunc.getNeverResolvedPromise();
130
+ // const p2 = UtilFunc.getNeverResolvedPromise();
131
+ // const p3 = JsFunc.getNeverResolvedPromise();
132
+ // const p4 = JsFunc.getNeverResolvedPromise();
133
+ // console.log(p1==p2);
134
+ // console.log(p2==p3);
135
+ // console.log(p3==p4);
136
+ // console.log(p3);
137
+ // console.log(2345);
138
+ //})();