@zwa73/utils 1.0.106 → 1.0.108

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.
@@ -18,26 +18,30 @@ export declare class Piper<Arg, Result = Arg> {
18
18
  }
19
19
  type StreamOperation<T, U> = (item: T) => Promise<U> | U;
20
20
  /**并行流 */
21
- export declare class Stream<T> {
21
+ export declare class Stream<T> implements Iterable<T> {
22
22
  /**并发数*/
23
23
  private _concurrent;
24
- /**原始列表*/
25
24
  private _list;
26
25
  /**加工函数列表*/
27
26
  private _operation;
28
- constructor(list: Array<T>, concurrent?: number);
27
+ constructor(base?: Array<T> | number, concurrent?: number);
29
28
  /**平分数组
30
29
  * @param count - 份数
31
30
  * @param mode - 模式 average:轮询平均分 chunk:切块均分
32
31
  * @returns 新数组
33
32
  */
34
33
  private divide;
35
- /**映射加工
34
+ /**转换流
35
+ * @param operation - 加工函数
36
+ * @returns 新流
37
+ */
38
+ private trans;
39
+ /**流式的 映射加工
36
40
  * @param operation - 加工函数
37
41
  * @returns 新流
38
42
  */
39
43
  map<U>(operation: StreamOperation<T, U>): Stream<U>;
40
- /**遍历
44
+ /**流式的 遍历
41
45
  * 返回自身
42
46
  * @param operation - 遍历函数
43
47
  * @returns 自身
@@ -47,9 +51,16 @@ export declare class Stream<T> {
47
51
  * @returns 自身
48
52
  */
49
53
  append(): Promise<Stream<T>>;
50
- /**转换为数组
54
+ /**应用加工 并转换为数组
51
55
  * @returns 数组
52
56
  */
53
57
  toArray(): Promise<Array<T>>;
58
+ /**应用加工 并过滤
59
+ * @param func - 过滤函数
60
+ * @returns 自身
61
+ */
62
+ filter(func: (value: T, index: number, array: T[]) => boolean): Promise<Stream<T>>;
63
+ [Symbol.iterator](): Iterator<T>;
64
+ get length(): number;
54
65
  }
55
66
  export {};
package/dist/UtilClass.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Stream = exports.Piper = void 0;
4
+ const QuickFunction_1 = require("./QuickFunction");
4
5
  /**函数管道器 */
5
6
  class Piper {
6
7
  /**管道函数列表 */
@@ -31,12 +32,16 @@ exports.Piper = Piper;
31
32
  class Stream {
32
33
  /**并发数*/
33
34
  _concurrent;
34
- /**原始列表*/
35
35
  _list;
36
36
  /**加工函数列表*/
37
37
  _operation = [];
38
- constructor(list, concurrent = 1) {
39
- this._list = list;
38
+ constructor(base, concurrent = 1) {
39
+ if (base == undefined)
40
+ this._list = new Array();
41
+ else if (typeof base === 'number')
42
+ this._list = new Array(base);
43
+ else
44
+ this._list = new Array(...base);
40
45
  this._concurrent = concurrent;
41
46
  }
42
47
  /**平分数组
@@ -48,22 +53,21 @@ class Stream {
48
53
  if (count <= 0)
49
54
  return [];
50
55
  if (count == 1)
51
- return [[...this._list]];
56
+ return [[...this]];
57
+ const size = this.length;
52
58
  const result = [];
53
- switch (mode) {
59
+ (0, QuickFunction_1.matchProc)(mode, {
54
60
  //轮询平均分
55
- case "average":
61
+ 'average': () => {
56
62
  for (let i = 0; i < count; i++) {
57
63
  const clist = [];
58
- const size = this._list.length;
59
64
  for (let j = i; j < size; j += count)
60
65
  clist.push(this._list[j]);
61
66
  result.push(clist);
62
67
  }
63
- break;
68
+ },
64
69
  //切块均分
65
- case "chunk":
66
- const size = this._list.length;
70
+ 'chunk': () => {
67
71
  const chunkSize = Math.ceil(size / count);
68
72
  for (let i = 0; i < count; i++) {
69
73
  const start = i * chunkSize;
@@ -72,19 +76,28 @@ class Stream {
72
76
  end = size;
73
77
  result.push(this._list.slice(start, end));
74
78
  }
75
- break;
76
- }
79
+ },
80
+ });
77
81
  return result;
78
82
  }
79
- /**映射加工
83
+ /**转换流
84
+ * @param operation - 加工函数
85
+ * @returns 新流
86
+ */
87
+ trans(operation) {
88
+ const ns = new Stream(this._list, this._concurrent);
89
+ ns._operation.push(...this._operation);
90
+ ns._operation.push(operation);
91
+ return ns;
92
+ }
93
+ /**流式的 映射加工
80
94
  * @param operation - 加工函数
81
95
  * @returns 新流
82
96
  */
83
97
  map(operation) {
84
- this._operation.push(operation);
85
- return this;
98
+ return this.trans(operation);
86
99
  }
87
- /**遍历
100
+ /**流式的 遍历
88
101
  * 返回自身
89
102
  * @param operation - 遍历函数
90
103
  * @returns 自身
@@ -94,8 +107,8 @@ class Stream {
94
107
  operation(item);
95
108
  return item;
96
109
  };
97
- this._operation.push(opera);
98
- return this;
110
+ return this.trans(opera);
111
+ ;
99
112
  }
100
113
  //终结操作
101
114
  /**应用加工
@@ -104,14 +117,12 @@ class Stream {
104
117
  async append() {
105
118
  if (this._operation.length == 0)
106
119
  return this;
107
- const promiseList = [];
120
+ const pList = [];
108
121
  //均分处理
109
- const sliceList = this.divide(this._concurrent);
110
- for (let i = 0; i < this._concurrent; i++) {
111
- const subList = sliceList[i];
122
+ this.divide(this._concurrent).forEach((subList) => {
112
123
  if (!subList)
113
- continue;
114
- promiseList.push(new Promise(async (reslove) => {
124
+ return;
125
+ pList.push(new Promise(async (reslove) => {
115
126
  const result = [];
116
127
  for (let item of subList) {
117
128
  if (!item)
@@ -122,28 +133,50 @@ class Stream {
122
133
  }
123
134
  reslove(result);
124
135
  }));
125
- }
126
- const nlist = await Promise.all(promiseList);
136
+ });
137
+ const rlist = await Promise.all(pList);
127
138
  //拼接结果 轮询均分
128
- const result = new Array(this._list.length).fill(undefined);
129
- for (let i = 0; i < this._concurrent; i++) {
130
- const subList = nlist[i];
139
+ const result = new Array(this.length).fill(undefined);
140
+ rlist.forEach((subList, i) => {
131
141
  if (!subList)
132
- continue;
142
+ return;
133
143
  const subSize = subList.length;
134
144
  for (let j = 0; j < subSize; j++)
135
145
  result[i + j * this._concurrent] = subList[j];
136
- }
146
+ });
137
147
  this._list = result;
138
148
  this._operation = [];
139
149
  return this;
140
150
  }
141
- /**转换为数组
151
+ /**应用加工 并转换为数组
142
152
  * @returns 数组
143
153
  */
144
154
  async toArray() {
145
155
  await this.append();
146
- return this._list;
156
+ return [...this];
157
+ }
158
+ /**应用加工 并过滤
159
+ * @param func - 过滤函数
160
+ * @returns 自身
161
+ */
162
+ async filter(func) {
163
+ await this.append();
164
+ return new Stream(this._list.filter(func));
165
+ }
166
+ //迭代器
167
+ [Symbol.iterator]() {
168
+ let index = 0;
169
+ const data = this._list;
170
+ return {
171
+ next: () => ({
172
+ value: data[index++],
173
+ done: index > data.length
174
+ })
175
+ };
176
+ }
177
+ // 创建 length 属性的 getter 和 setter
178
+ get length() {
179
+ return this._list.length;
147
180
  }
148
181
  }
149
182
  exports.Stream = Stream;
@@ -34,10 +34,10 @@ export declare namespace UtilCodec {
34
34
  * @param arr = Token数组
35
35
  * @returns 消息字符串
36
36
  */
37
- function decodeTokenTurbo(arr: Uint32Array): string;
37
+ function decodeTokenTurbo(arr: Uint32Array | number[]): string;
38
38
  /**token解码 Davinci模型
39
39
  * @param arr = Token数组
40
40
  * @returns 消息字符串
41
41
  */
42
- function decodeTokenDavinci(arr: Uint32Array): string;
42
+ function decodeTokenDavinci(arr: Uint32Array | number[]): string;
43
43
  }
@@ -1,10 +1,30 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
4
24
  };
5
25
  Object.defineProperty(exports, "__esModule", { value: true });
6
26
  exports.UtilCodec = void 0;
7
- const html_entities_1 = __importDefault(require("html-entities"));
27
+ const he = __importStar(require("html-entities"));
8
28
  const tiktoken_1 = require("tiktoken");
9
29
  /**编码/解码器 */
10
30
  var UtilCodec;
@@ -17,7 +37,7 @@ var UtilCodec;
17
37
  * @returns 转换后的字符串
18
38
  */
19
39
  function decodeHtmlEntities(str) {
20
- return html_entities_1.default.decode(str);
40
+ return he.decode(str);
21
41
  }
22
42
  UtilCodec.decodeHtmlEntities = decodeHtmlEntities;
23
43
  /**HTML实体编码 将一个字符串中的 需编码字符转换为 HTML实体
@@ -25,7 +45,7 @@ var UtilCodec;
25
45
  * @returns 转换后的字符串
26
46
  */
27
47
  function encodeHtmlEntities(str) {
28
- return html_entities_1.default.encode(str);
48
+ return he.encode(str);
29
49
  }
30
50
  UtilCodec.encodeHtmlEntities = encodeHtmlEntities;
31
51
  //#region LAM
@@ -83,6 +103,8 @@ var UtilCodec;
83
103
  */
84
104
  function decodeTokenTurbo(arr) {
85
105
  initTikTokenEncoder();
106
+ if (Array.isArray(arr))
107
+ arr = new Uint32Array(arr);
86
108
  return textDecoder.decode(encoderTurbo?.decode(arr));
87
109
  }
88
110
  UtilCodec.decodeTokenTurbo = decodeTokenTurbo;
@@ -92,6 +114,8 @@ var UtilCodec;
92
114
  */
93
115
  function decodeTokenDavinci(arr) {
94
116
  initTikTokenEncoder();
117
+ if (Array.isArray(arr))
118
+ arr = new Uint32Array(arr);
95
119
  return textDecoder.decode(encoderDavinci?.decode(arr));
96
120
  }
97
121
  UtilCodec.decodeTokenDavinci = decodeTokenDavinci;
@@ -164,7 +164,7 @@ class SFfmpegTool {
164
164
  static async wav2oggMP(ioMap, quality = 10, cpCount = 16) {
165
165
  await new UtilClass_1.Stream(Object.entries(ioMap))
166
166
  .map(async ([inPath, outPath]) => {
167
- UtilLogger_1.SLogger.info("SFfmpegTool.wav2oggMP 正在处理:" + outPath);
167
+ UtilLogger_1.SLogger.info(`SFfmpegTool.wav2oggMP 正在处理:${outPath}`);
168
168
  await SFfmpegTool.wav2ogg(inPath, outPath, quality);
169
169
  })
170
170
  .append();
@@ -177,7 +177,7 @@ class SFfmpegTool {
177
177
  static async flac2oggMP(ioMap, quality = 10, cpCount = 16) {
178
178
  await new UtilClass_1.Stream(Object.entries(ioMap))
179
179
  .map(async ([inPath, outPath]) => {
180
- UtilLogger_1.SLogger.info("SFfmpegTool.flac2oggMP 正在处理:" + outPath);
180
+ UtilLogger_1.SLogger.info(`SFfmpegTool.flac2oggMP 正在处理:${outPath}`);
181
181
  await SFfmpegTool.flac2ogg(inPath, outPath, quality);
182
182
  })
183
183
  .append();
@@ -190,7 +190,7 @@ class SFfmpegTool {
190
190
  static async trimSilenceMP(ioMap, threshold = -50, silence = 0.2, cpCount = 16) {
191
191
  await new UtilClass_1.Stream(Object.entries(ioMap))
192
192
  .map(async ([inPath, outPath]) => {
193
- UtilLogger_1.SLogger.info("SFfmpegTool.trimSilenceMP 正在处理:" + outPath);
193
+ UtilLogger_1.SLogger.info(`SFfmpegTool.trimSilenceMP 正在处理:${outPath}`);
194
194
  await SFfmpegTool.trimSilence(inPath, outPath, threshold, silence);
195
195
  })
196
196
  .append();
@@ -203,7 +203,7 @@ class SFfmpegTool {
203
203
  static async resampleMP(ioMap, rate = 22050, cpCount = 16) {
204
204
  await new UtilClass_1.Stream(Object.entries(ioMap))
205
205
  .map(async ([inPath, outPath]) => {
206
- UtilLogger_1.SLogger.info("SFfmpegTool.resampleMP 正在处理:" + outPath);
206
+ UtilLogger_1.SLogger.info(`SFfmpegTool.resampleMP 正在处理:${outPath}`);
207
207
  await SFfmpegTool.resample(inPath, outPath, rate);
208
208
  })
209
209
  .append();
@@ -98,21 +98,21 @@ export declare namespace UtilFT {
98
98
  */
99
99
  function writeJSONFile(filePath: string, token: JToken): Promise<void>;
100
100
  /**搜索路径符合正则表达式的文件
101
- * @param folder - 文件夹路径
101
+ * @param dir - 起始目录
102
102
  * @param traitRegex - 正则表达式
103
103
  * @param opt - 可选参数
104
104
  * @param opt.relative - 搜索子目录
105
105
  * @returns 文件名路径数组
106
106
  */
107
- function fileSearchRegex(folder: string, traitRegex: string, opt?: FileSearchRegexOpt): string[];
107
+ function fileSearchRegex(dir: string, traitRegex: string, opt?: FileSearchRegexOpt): string[];
108
108
  /**搜索符合Glob匹配的文件
109
- * @param folder - 文件夹路径
109
+ * @param dir - 起始目录
110
110
  * @param globPattern - glob匹配
111
111
  * @param opt - 可选参数
112
112
  * @param opt.ignore - 忽略的文件
113
113
  * @returns 文件绝对路径数组
114
114
  */
115
- function fileSearchGlob(folder: string, globPattern: string | string[], opt?: FileSearchGlobOpt): string[];
115
+ function fileSearchGlob(dir: string, globPattern: string | string[], opt?: FileSearchGlobOpt): string[];
116
116
  /**
117
117
  * @deprecated 请使用 fileSearchRegex 或 fileSearchGlob
118
118
  */
@@ -194,19 +194,19 @@ var UtilFT;
194
194
  }
195
195
  UtilFT.writeJSONFile = writeJSONFile;
196
196
  /**搜索路径符合正则表达式的文件
197
- * @param folder - 文件夹路径
197
+ * @param dir - 起始目录
198
198
  * @param traitRegex - 正则表达式
199
199
  * @param opt - 可选参数
200
200
  * @param opt.relative - 搜索子目录
201
201
  * @returns 文件名路径数组
202
202
  */
203
- function fileSearchRegex(folder, traitRegex, opt) {
203
+ function fileSearchRegex(dir, traitRegex, opt) {
204
204
  const relative = opt?.relative ?? true;
205
205
  const outArray = [];
206
- const subFiles = fs.readdirSync(folder, { withFileTypes: true });
206
+ const subFiles = fs.readdirSync(dir, { withFileTypes: true });
207
207
  const regex = new RegExp(traitRegex);
208
208
  for (const subFile of subFiles) {
209
- const subFilePath = path.join(folder, subFile.name);
209
+ const subFilePath = path.join(dir, subFile.name);
210
210
  //判断是否是文件夹,递归调用
211
211
  if (subFile.isDirectory()) {
212
212
  if (relative)
@@ -220,16 +220,16 @@ var UtilFT;
220
220
  }
221
221
  UtilFT.fileSearchRegex = fileSearchRegex;
222
222
  /**搜索符合Glob匹配的文件
223
- * @param folder - 文件夹路径
223
+ * @param dir - 起始目录
224
224
  * @param globPattern - glob匹配
225
225
  * @param opt - 可选参数
226
226
  * @param opt.ignore - 忽略的文件
227
227
  * @returns 文件绝对路径数组
228
228
  */
229
- function fileSearchGlob(folder, globPattern, opt) {
229
+ function fileSearchGlob(dir, globPattern, opt) {
230
230
  const fixedPath = typeof globPattern === "string"
231
- ? path.join(folder, path.posix.normalize(globPattern))
232
- : globPattern.map((p) => path.join(folder, path.posix.normalize(p)));
231
+ ? path.join(dir, path.posix.normalize(globPattern))
232
+ : globPattern.map((p) => path.join(dir, path.posix.normalize(p)));
233
233
  return (0, glob_1.globSync)(fixedPath, { ignore: opt?.ingore, absolute: true });
234
234
  }
235
235
  UtilFT.fileSearchGlob = fileSearchGlob;
@@ -1,4 +1,4 @@
1
- import { AnyFunc, ComposedClass, ComposedMixinable, ExtractOutcome, IJData, JObject, JToken, Keyable, LiteralCheck, Matchable, MatchableFlag, Mixinable, Outcome, PromiseVerifyFn, UnionToIntersection } from "./UtilInterfaces";
1
+ import { AnyFunc, ComposedClass, ComposedMixinable, ComposedRefMixinable, ExtractOutcome, IJData, JObject, JToken, Keyable, LiteralCheck, Matchable, MatchableFlag, Mixinable, Outcome, PromiseVerifyFn, RefMixinable, UnionToIntersection } from "./UtilInterfaces";
2
2
  import { LogLevel } from "./UtilLogger";
3
3
  import { FailedLike, None, StatusSymbol, Success, SuccessLike, Timeout } from "./UtilSymbol";
4
4
  type SuccessOut<T> = Outcome<Success, T>;
@@ -82,8 +82,12 @@ export declare class UtilFunc {
82
82
  * @returns 混合完成的类
83
83
  */
84
84
  static composeClassPart<Base extends object, Mixin extends object, Field extends keyof Mixin>(base: Base, mixin: Mixin, key: string, ...fields: Field[]): ComposedClass<Base, Mixin, typeof key, Field>;
85
- /**根据 MIXIN_FIELDS 自动混入 */
85
+ /**根据 MIXIN_FIELDS 自动混入
86
+ * @deprecated 非必要情况下, 对class定义请使用 composeRefMixinable
87
+ */
86
88
  static composeMixinable<Base extends object, Mixins extends Mixinable<any>[]>(base: Base, ...mixins: Mixins): ComposedMixinable<Base, Mixins>;
89
+ /**根据 MIXIN_FIELDS 自动混入 */
90
+ static composeRefMixinable<Base extends object, Mixins extends RefMixinable<any, unknown>[]>(base: Base, ...mixins: Mixins): ComposedRefMixinable<Base, Mixins>;
87
91
  /**对对象的每个属性应用映射函数,并返回一个新的对象。
88
92
  * @template T - 对象的类型
89
93
  * @param obj - 要处理的对象
@@ -255,17 +255,21 @@ class UtilFunc {
255
255
  for (const fd of fields) {
256
256
  if (compObj[fd] !== undefined)
257
257
  UtilLogger_1.SLogger.warn(`field: ${fd} 已存在于基础类中, 混入可能导致类型问题, 如需覆盖, 请使用 ${key}=val`);
258
- //Object.defineProperty(compObj, fd, {
259
- // get: ()=>compObj[key][fd],
260
- // set: (value)=>{compObj[key][fd] = value},
261
- // enumerable:true ,
262
- // //writable: true ,
263
- // configurable: true
264
- //});
258
+ //func需绑定this无法直接设置属性
265
259
  if (typeof mixin[fd] === 'function') {
266
260
  compObj[fd] = (...args) => compObj[key][fd](...args);
261
+ //#region other
262
+ //const memo = (...args: any[]) => compObj[key][fd](...args);
263
+ //Object.defineProperty(compObj, fd, {
264
+ // get:()=>memo,
265
+ // set:()=>SLogger.warn(new Error(`试图修改一个由 composeClassPart 组合的函数字段:${String(fd)}, 修改已被忽略`)),
266
+ // enumerable:true ,
267
+ // //writable: true ,
268
+ // configurable: true
269
+ //});
267
270
  //(compObj as any)[fd] = (...args: any[]) => (mixin[fd] as any).apply(mixin, args);
268
271
  //(compObj as any)[fd] = (mixin[fd] as any).bind(mixin);
272
+ //#endregion
269
273
  }
270
274
  else {
271
275
  Object.defineProperty(compObj, fd, {
@@ -279,7 +283,9 @@ class UtilFunc {
279
283
  }
280
284
  return compObj;
281
285
  }
282
- /**根据 MIXIN_FIELDS 自动混入 */
286
+ /**根据 MIXIN_FIELDS 自动混入
287
+ * @deprecated 非必要情况下, 对class定义请使用 composeRefMixinable
288
+ */
283
289
  static composeMixinable(base, ...mixins) {
284
290
  let out = base;
285
291
  const fieldsSet = new Set();
@@ -296,6 +302,23 @@ class UtilFunc {
296
302
  }
297
303
  return out;
298
304
  }
305
+ /**根据 MIXIN_FIELDS 自动混入 */
306
+ static composeRefMixinable(base, ...mixins) {
307
+ let out = base;
308
+ const fieldsSet = new Set();
309
+ for (const mixin of mixins) {
310
+ const ctor = mixin.CTOR;
311
+ for (const field of ctor.MIXIN_FIELDS) {
312
+ const fixField = field;
313
+ if (fieldsSet.has(fixField))
314
+ UtilLogger_1.SLogger.warn(`composeMixinable 出现了重复的 field: ${fixField} 可能会导致问题`);
315
+ else
316
+ fieldsSet.add(fixField);
317
+ }
318
+ out = UtilFunc.composeClassPart(base, mixin, ctor.MIXIN_KEY, ...ctor.MIXIN_FIELDS);
319
+ }
320
+ return out;
321
+ }
299
322
  /**对对象的每个属性应用映射函数,并返回一个新的对象。
300
323
  * @template T - 对象的类型
301
324
  * @param obj - 要处理的对象
@@ -105,8 +105,29 @@ export type Mixinable<Mixin> = {
105
105
  */
106
106
  readonly MIXIN_FIELDS: readonly (keyof Mixin)[];
107
107
  };
108
- /**自动组合可混入的类 */
108
+ /**是原型构造器类型 */
109
+ export type IsCtor<T> = T extends {
110
+ new (): infer Ins;
111
+ } ? T : never;
112
+ /**可反射的
113
+ * @template Ctor - 构造器类型
114
+ * @template Constraint - 构造器约束
115
+ */
116
+ export type ReflectionAble<Ctor, Constraint = {}> = {
117
+ /**原型构造器 */
118
+ readonly CTOR: Ctor & Constraint;
119
+ };
120
+ /**可反射的 且 构造函数是可混入的类
121
+ * @template Ctor - 构造器类型
122
+ * @template Instance - 实例类型
123
+ * @template Constraint - 构造器约束
124
+ */
125
+ export type RefMixinable<Ctor, Instance, Constraint = {}> = ReflectionAble<Ctor, Mixinable<Instance> & Constraint>;
126
+ /**自动组合可混入的类
127
+ */
109
128
  export type ComposedMixinable<B, Ms extends unknown[]> = Ms extends [infer M, ...infer Rest] ? M extends Mixinable<M> ? ComposedMixinable<ComposedClass<B, M, M['MIXIN_KEY'], M['MIXIN_FIELDS'][number]>, Rest> : "一个混入类没有实现 Mixinable<self>" & Error : B;
129
+ /**自动组合 可反射的 且 构造函数是可混入的 类 */
130
+ export type ComposedRefMixinable<B, Ms extends unknown[]> = Ms extends [infer M, ...infer Rest] ? M extends RefMixinable<unknown, M> ? ComposedRefMixinable<ComposedClass<B, M, M['CTOR']['MIXIN_KEY'], M['CTOR']['MIXIN_FIELDS'][number]>, Rest> : "一个混入类没有实现 RefMixinable<typeof self, self>" & Error : B;
110
131
  /** extends封装
111
132
  * @template B - 基础类型
112
133
  * @template T - 判断的目标类型
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zwa73/utils",
3
- "version": "1.0.106",
3
+ "version": "1.0.108",
4
4
  "description": "my utils",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/UtilClass.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { matchProc } from "./QuickFunction";
2
+
1
3
  /**函数管道器 */
2
4
  export class Piper<Arg, Result = Arg> {
3
5
  /**管道函数列表 */
@@ -35,15 +37,16 @@ export class Piper<Arg, Result = Arg> {
35
37
 
36
38
  type StreamOperation<T, U> = (item: T)=>Promise<U>|U;
37
39
  /**并行流 */
38
- export class Stream<T> {
40
+ export class Stream<T> implements Iterable<T>{
39
41
  /**并发数*/
40
42
  private _concurrent: number;
41
- /**原始列表*/
42
43
  private _list: T[];
43
44
  /**加工函数列表*/
44
45
  private _operation: Array<StreamOperation<T, T>> = [];
45
- constructor(list: Array<T>, concurrent: number = 1) {
46
- this._list = list;
46
+ constructor(base?: Array<T>|number, concurrent: number = 1) {
47
+ if(base==undefined) this._list = new Array();
48
+ else if(typeof base === 'number') this._list = new Array(base);
49
+ else this._list = new Array(...base);
47
50
  this._concurrent = concurrent;
48
51
  }
49
52
  /**平分数组
@@ -53,23 +56,22 @@ export class Stream<T> {
53
56
  */
54
57
  private divide(count: number, mode: "average" | "chunk" = "average"): T[][] {
55
58
  if (count <= 0) return [];
56
- if (count == 1) return [[...this._list]];
59
+ if (count == 1) return [[...this]];
60
+ const size = this.length;
61
+ const result:T[][] = [];
57
62
 
58
- const result = [];
59
- switch (mode) {
63
+ matchProc(mode,{
60
64
  //轮询平均分
61
- case "average":
65
+ 'average':()=>{
62
66
  for (let i = 0; i < count; i++) {
63
67
  const clist = [];
64
- const size = this._list.length;
65
68
  for (let j = i; j < size; j += count)
66
69
  clist.push(this._list[j]);
67
70
  result.push(clist);
68
71
  }
69
- break;
72
+ },
70
73
  //切块均分
71
- case "chunk":
72
- const size = this._list.length;
74
+ 'chunk':()=>{
73
75
  const chunkSize = Math.ceil(size / count);
74
76
  for (let i = 0; i < count; i++) {
75
77
  const start = i * chunkSize;
@@ -77,20 +79,29 @@ export class Stream<T> {
77
79
  if (end > size) end = size;
78
80
  result.push(this._list.slice(start, end));
79
81
  }
80
- break;
81
- }
82
+ },
83
+ })
82
84
  return result;
83
85
  }
86
+ /**转换流
87
+ * @param operation - 加工函数
88
+ * @returns 新流
89
+ */
90
+ private trans<U>(operation:StreamOperation<T, U>): Stream<U>{
91
+ const ns = new Stream(this._list,this._concurrent);
92
+ ns._operation.push(...this._operation);
93
+ ns._operation.push(operation as any);
94
+ return ns as any;
95
+ }
84
96
 
85
- /**映射加工
97
+ /**流式的 映射加工
86
98
  * @param operation - 加工函数
87
99
  * @returns 新流
88
100
  */
89
101
  map<U>(operation: StreamOperation<T, U>): Stream<U> {
90
- this._operation.push(operation as any);
91
- return this as any as Stream<U>;
102
+ return this.trans(operation);
92
103
  }
93
- /**遍历
104
+ /**流式的 遍历
94
105
  * 返回自身
95
106
  * @param operation - 遍历函数
96
107
  * @returns 自身
@@ -100,8 +111,7 @@ export class Stream<T> {
100
111
  operation(item);
101
112
  return item;
102
113
  };
103
- this._operation.push(opera);
104
- return this;
114
+ return this.trans(opera);;
105
115
  }
106
116
 
107
117
  //终结操作
@@ -111,13 +121,11 @@ export class Stream<T> {
111
121
  async append(): Promise<Stream<T>> {
112
122
  if (this._operation.length == 0) return this;
113
123
 
114
- const promiseList: Promise<T[]>[] = [];
124
+ const pList: Promise<T[]>[] = [];
115
125
  //均分处理
116
- const sliceList = this.divide(this._concurrent);
117
- for (let i = 0; i < this._concurrent; i++) {
118
- const subList = sliceList[i];
119
- if (!subList) continue;
120
- promiseList.push(
126
+ this.divide(this._concurrent).forEach((subList)=>{
127
+ if (!subList) return;
128
+ pList.push(
121
129
  new Promise(async (reslove) => {
122
130
  const result:T[] = [];
123
131
  for (let item of subList) {
@@ -129,27 +137,52 @@ export class Stream<T> {
129
137
  reslove(result);
130
138
  })
131
139
  );
132
- }
133
- const nlist = await Promise.all(promiseList);
140
+ })
141
+ const rlist = await Promise.all(pList);
142
+
134
143
  //拼接结果 轮询均分
135
- const result = new Array(this._list.length).fill(undefined);
136
- for (let i = 0; i < this._concurrent; i++) {
137
- const subList = nlist[i];
138
- if (!subList) continue;
144
+ const result = new Array(this.length).fill(undefined);
145
+ rlist.forEach((subList,i)=>{
146
+ if (!subList) return;
139
147
  const subSize = subList.length;
140
148
  for (let j = 0; j < subSize; j++)
141
149
  result[i + j * this._concurrent] = subList[j];
142
- }
150
+ });
151
+
143
152
  this._list = result;
144
153
  this._operation = [];
145
154
  return this;
146
155
  }
147
- /**转换为数组
156
+ /**应用加工 并转换为数组
148
157
  * @returns 数组
149
158
  */
150
159
  async toArray(): Promise<Array<T>> {
151
160
  await this.append();
152
- return this._list;
161
+ return [...this];
153
162
  }
154
- }
163
+ /**应用加工 并过滤
164
+ * @param func - 过滤函数
165
+ * @returns 自身
166
+ */
167
+ async filter(func:(value: T, index: number, array: T[])=>boolean): Promise<Stream<T>>{
168
+ await this.append();
169
+ return new Stream(this._list.filter(func));
170
+ }
171
+ //迭代器
172
+ [Symbol.iterator](): Iterator<T> {
173
+ let index = 0;
174
+ const data = this._list;
155
175
 
176
+ return {
177
+ next: () => ({
178
+ value: data[index++],
179
+ done: index > data.length
180
+ })
181
+ };
182
+ }
183
+
184
+ // 创建 length 属性的 getter 和 setter
185
+ get length(): number {
186
+ return this._list.length;
187
+ }
188
+ }
package/src/UtilCodecs.ts CHANGED
@@ -1,4 +1,4 @@
1
- import he from 'html-entities';
1
+ import * as he from 'html-entities';
2
2
  import {get_encoding,Tiktoken} from 'tiktoken';
3
3
 
4
4
 
@@ -81,16 +81,18 @@ export function encodeTokenDavinci(str:string):Uint32Array{
81
81
  * @param arr = Token数组
82
82
  * @returns 消息字符串
83
83
  */
84
- export function decodeTokenTurbo(arr:Uint32Array):string{
84
+ export function decodeTokenTurbo(arr:Uint32Array|number[]):string{
85
85
  initTikTokenEncoder();
86
+ if(Array.isArray(arr)) arr = new Uint32Array(arr);
86
87
  return textDecoder.decode(encoderTurbo?.decode(arr));
87
88
  }
88
89
  /**token解码 Davinci模型
89
90
  * @param arr = Token数组
90
91
  * @returns 消息字符串
91
92
  */
92
- export function decodeTokenDavinci(arr:Uint32Array):string{
93
+ export function decodeTokenDavinci(arr:Uint32Array|number[]):string{
93
94
  initTikTokenEncoder();
95
+ if(Array.isArray(arr)) arr = new Uint32Array(arr);
94
96
  return textDecoder.decode(encoderDavinci?.decode(arr));
95
97
  }
96
98
  //#endregion
@@ -168,7 +168,7 @@ class SFfmpegTool {
168
168
  static async wav2oggMP(ioMap: IOMap, quality = 10, cpCount = 16) {
169
169
  await new Stream(Object.entries(ioMap))
170
170
  .map(async ([inPath, outPath]) => {
171
- SLogger.info("SFfmpegTool.wav2oggMP 正在处理:" + outPath);
171
+ SLogger.info(`SFfmpegTool.wav2oggMP 正在处理:${outPath}`);
172
172
  await SFfmpegTool.wav2ogg(inPath, outPath, quality);
173
173
  })
174
174
  .append();
@@ -185,7 +185,7 @@ class SFfmpegTool {
185
185
  ) {
186
186
  await new Stream(Object.entries(ioMap))
187
187
  .map(async ([inPath, outPath]) => {
188
- SLogger.info("SFfmpegTool.flac2oggMP 正在处理:" + outPath);
188
+ SLogger.info(`SFfmpegTool.flac2oggMP 正在处理:${outPath}`);
189
189
  await SFfmpegTool.flac2ogg(inPath, outPath, quality);
190
190
  })
191
191
  .append();
@@ -203,7 +203,7 @@ class SFfmpegTool {
203
203
  ) {
204
204
  await new Stream(Object.entries(ioMap))
205
205
  .map(async ([inPath, outPath]) => {
206
- SLogger.info("SFfmpegTool.trimSilenceMP 正在处理:" + outPath);
206
+ SLogger.info(`SFfmpegTool.trimSilenceMP 正在处理:${outPath}`);
207
207
  await SFfmpegTool.trimSilence(inPath, outPath, threshold, silence);
208
208
  })
209
209
  .append();
@@ -217,7 +217,7 @@ class SFfmpegTool {
217
217
  static async resampleMP(ioMap: IOMap, rate: number = 22050, cpCount: number = 16) {
218
218
  await new Stream(Object.entries(ioMap))
219
219
  .map(async ([inPath, outPath]) => {
220
- SLogger.info("SFfmpegTool.resampleMP 正在处理:" + outPath);
220
+ SLogger.info(`SFfmpegTool.resampleMP 正在处理:${outPath}`);
221
221
  await SFfmpegTool.resample(inPath, outPath, rate);
222
222
  })
223
223
  .append();
@@ -228,19 +228,19 @@ export async function writeJSONFile(
228
228
  }
229
229
 
230
230
  /**搜索路径符合正则表达式的文件
231
- * @param folder - 文件夹路径
231
+ * @param dir - 起始目录
232
232
  * @param traitRegex - 正则表达式
233
233
  * @param opt - 可选参数
234
234
  * @param opt.relative - 搜索子目录
235
235
  * @returns 文件名路径数组
236
236
  */
237
- export function fileSearchRegex(folder: string, traitRegex: string, opt?:FileSearchRegexOpt) {
237
+ export function fileSearchRegex(dir: string, traitRegex: string, opt?:FileSearchRegexOpt) {
238
238
  const relative = opt?.relative ?? true;
239
239
  const outArray: string[] = [];
240
- const subFiles = fs.readdirSync(folder,{withFileTypes:true});
240
+ const subFiles = fs.readdirSync(dir,{withFileTypes:true});
241
241
  const regex = new RegExp(traitRegex);
242
242
  for (const subFile of subFiles) {
243
- const subFilePath = path.join(folder, subFile.name);
243
+ const subFilePath = path.join(dir, subFile.name);
244
244
  //判断是否是文件夹,递归调用
245
245
  if (subFile.isDirectory()) {
246
246
  if(relative) outArray.push(...fileSearchRegex(path.join(subFilePath, path.sep), traitRegex));
@@ -251,16 +251,16 @@ export function fileSearchRegex(folder: string, traitRegex: string, opt?:FileSea
251
251
  return outArray;
252
252
  }
253
253
  /**搜索符合Glob匹配的文件
254
- * @param folder - 文件夹路径
254
+ * @param dir - 起始目录
255
255
  * @param globPattern - glob匹配
256
256
  * @param opt - 可选参数
257
257
  * @param opt.ignore - 忽略的文件
258
258
  * @returns 文件绝对路径数组
259
259
  */
260
- export function fileSearchGlob(folder: string, globPattern:string|string[],opt?:FileSearchGlobOpt){
260
+ export function fileSearchGlob(dir: string, globPattern:string|string[],opt?:FileSearchGlobOpt){
261
261
  const fixedPath = typeof globPattern === "string"
262
- ? path.join(folder,path.posix.normalize(globPattern))
263
- : globPattern.map((p)=>path.join(folder,path.posix.normalize(p)));
262
+ ? path.join(dir,path.posix.normalize(globPattern))
263
+ : globPattern.map((p)=>path.join(dir,path.posix.normalize(p)));
264
264
  return globSync(fixedPath,{ignore:opt?.ingore,absolute:true});
265
265
  }
266
266
  /**
@@ -1,5 +1,5 @@
1
1
  import * as crypto from "crypto";
2
- import { AnyFunc, ComposedClass, ComposedMixinable, ExtractOutcome, IJData, JObject, JToken, Keyable, LiteralCheck, Matchable, MatchableFlag, Mixinable, Outcome, PromiseStat, PromiseVerifyFn, UnionToIntersection } from "@src/UtilInterfaces";
2
+ import { AnyFunc, ComposedClass, ComposedMixinable, ComposedRefMixinable, ExtractOutcome, IJData, JObject, JToken, Keyable, LiteralCheck, Matchable, MatchableFlag, Mixinable, Outcome, PromiseStat, PromiseVerifyFn, RefMixinable, UnionToIntersection } from "@src/UtilInterfaces";
3
3
  import * as cp from "child_process";
4
4
  import { LogLevel, SLogger } from "@src/UtilLogger";
5
5
  import { Completed, Failed, FailedLike, None, StatusSymbol, Success, SuccessLike, Terminated, Timeout } from "./UtilSymbol";
@@ -280,17 +280,21 @@ static composeClassPart
280
280
  for(const fd of fields){
281
281
  if(compObj[fd]!==undefined)
282
282
  SLogger.warn(`field: ${fd as string} 已存在于基础类中, 混入可能导致类型问题, 如需覆盖, 请使用 ${key}=val`);
283
- //Object.defineProperty(compObj, fd, {
284
- // get: ()=>compObj[key][fd],
285
- // set: (value)=>{compObj[key][fd] = value},
286
- // enumerable:true ,
287
- // //writable: true ,
288
- // configurable: true
289
- //});
283
+ //func需绑定this无法直接设置属性
290
284
  if(typeof mixin[fd] === 'function') {
291
285
  compObj[fd] = (...args: any[]) => compObj[key][fd](...args);
286
+ //#region other
287
+ //const memo = (...args: any[]) => compObj[key][fd](...args);
288
+ //Object.defineProperty(compObj, fd, {
289
+ // get:()=>memo,
290
+ // set:()=>SLogger.warn(new Error(`试图修改一个由 composeClassPart 组合的函数字段:${String(fd)}, 修改已被忽略`)),
291
+ // enumerable:true ,
292
+ // //writable: true ,
293
+ // configurable: true
294
+ //});
292
295
  //(compObj as any)[fd] = (...args: any[]) => (mixin[fd] as any).apply(mixin, args);
293
296
  //(compObj as any)[fd] = (mixin[fd] as any).bind(mixin);
297
+ //#endregion
294
298
  } else {
295
299
  Object.defineProperty(compObj, fd, {
296
300
  get: ()=>compObj[key][fd],
@@ -304,7 +308,9 @@ static composeClassPart
304
308
  return compObj;
305
309
  }
306
310
 
307
- /**根据 MIXIN_FIELDS 自动混入 */
311
+ /**根据 MIXIN_FIELDS 自动混入
312
+ * @deprecated 非必要情况下, 对class定义请使用 composeRefMixinable
313
+ */
308
314
  static composeMixinable
309
315
  <Base extends object, Mixins extends Mixinable<any>[]>
310
316
  (base:Base,...mixins:Mixins):
@@ -325,6 +331,27 @@ static composeMixinable
325
331
  return out as any;
326
332
  }
327
333
 
334
+ /**根据 MIXIN_FIELDS 自动混入 */
335
+ static composeRefMixinable
336
+ <Base extends object, Mixins extends RefMixinable<any,unknown>[]>
337
+ (base:Base,...mixins:Mixins):
338
+ ComposedRefMixinable<Base,Mixins>{
339
+ let out = base;
340
+ const fieldsSet = new Set<string>();
341
+ for(const mixin of mixins){
342
+ const ctor = mixin.CTOR;
343
+ for(const field of ctor.MIXIN_FIELDS) {
344
+ const fixField = field as string;
345
+ if(fieldsSet.has(fixField))
346
+ SLogger.warn(`composeMixinable 出现了重复的 field: ${fixField} 可能会导致问题`);
347
+ else
348
+ fieldsSet.add(fixField);
349
+ }
350
+ out = UtilFunc.composeClassPart(base,mixin,ctor.MIXIN_KEY,...ctor.MIXIN_FIELDS);
351
+ }
352
+ return out as any;
353
+ }
354
+
328
355
 
329
356
  /**对对象的每个属性应用映射函数,并返回一个新的对象。
330
357
  * @template T - 对象的类型
@@ -141,8 +141,28 @@ export type Mixinable<Mixin> = {
141
141
  */
142
142
  readonly MIXIN_FIELDS: readonly (keyof Mixin)[];
143
143
  };
144
+ /**是原型构造器类型 */
145
+ export type IsCtor<T> = T extends {new():infer Ins}
146
+ ? T : never;
147
+ /**可反射的
148
+ * @template Ctor - 构造器类型
149
+ * @template Constraint - 构造器约束
150
+ */
151
+ export type ReflectionAble<Ctor,Constraint={}> = {
152
+ /**原型构造器 */
153
+ readonly CTOR:Ctor&Constraint
154
+ };
155
+ /**可反射的 且 构造函数是可混入的类
156
+ * @template Ctor - 构造器类型
157
+ * @template Instance - 实例类型
158
+ * @template Constraint - 构造器约束
159
+ */
160
+ export type RefMixinable<Ctor,Instance,Constraint={}> =
161
+ ReflectionAble<Ctor,Mixinable<Instance>&Constraint>;
144
162
 
145
- /**自动组合可混入的类 */
163
+
164
+ /**自动组合可混入的类
165
+ */
146
166
  export type ComposedMixinable<B, Ms extends unknown[]> =
147
167
  Ms extends [infer M, ...infer Rest]
148
168
  ? M extends Mixinable<M>
@@ -150,6 +170,17 @@ export type ComposedMixinable<B, Ms extends unknown[]> =
150
170
  : "一个混入类没有实现 Mixinable<self>" & Error
151
171
  : B
152
172
 
173
+ /**自动组合 可反射的 且 构造函数是可混入的 类 */
174
+ export type ComposedRefMixinable<B, Ms extends unknown[]> =
175
+ Ms extends [infer M, ...infer Rest]
176
+ ? M extends RefMixinable<unknown,M>
177
+ ? ComposedRefMixinable<ComposedClass<B,M,
178
+ M['CTOR']['MIXIN_KEY'],
179
+ M['CTOR']['MIXIN_FIELDS'][number]>,
180
+ Rest>
181
+ : "一个混入类没有实现 RefMixinable<typeof self, self>" & Error
182
+ : B
183
+
153
184
  /** extends封装
154
185
  * @template B - 基础类型
155
186
  * @template T - 判断的目标类型
@@ -166,8 +197,7 @@ export type ExtendThen<B,T,Y,N = never> = B extends T ? Y : N;
166
197
  */
167
198
  type UnionInclude<B,T,Y,N = never> =
168
199
  B extends Exclude<B,T>
169
- ? N
170
- : Y
200
+ ? N : Y
171
201
  /**排除可选字段 */
172
202
  export type RequiredOnly<T> = {
173
203
  [K in keyof T as
@@ -214,3 +244,5 @@ export type ExtractOutcome<T,K extends Keyable> =
214
244
  * 输出schema后替换为 ^.*$ 的 string 匹配
215
245
  */
216
246
  export type SchemaString = `${string}SchemaString`;
247
+
248
+