@zwa73/utils 1.0.91 → 1.0.93

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/src/UtilCodecs.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as he from 'html-entities';
1
+ import he from 'html-entities';
2
2
  import {get_encoding,Tiktoken} from 'tiktoken';
3
3
 
4
4
 
@@ -11,27 +11,11 @@ let encoderTurbo:Tiktoken|null = null;
11
11
  let encoderDavinci:Tiktoken|null = null;
12
12
  const textDecoder = new TextDecoder();
13
13
 
14
- // 定义一个对象,存储常见的HTML实体和对应的字符
15
- let htmlEntities:Record<string,string> = {
16
- "&lt;": "<",
17
- "&gt;": ">",
18
- "&amp;": "&",
19
- "&quot;": "\"",
20
- "&#39;": "'",
21
- "&#91;": "[",
22
- "&#93;": "]"
23
- };
24
-
25
14
  /**HTML实体解码 将一个字符串中的HTML实体转换为对应的字符
26
15
  * @param str - 要转换的字符串
27
16
  * @returns 转换后的字符串
28
17
  */
29
18
  export function decodeHtmlEntities(str:string) {
30
- //for(let code in htmlEntities){
31
- // let cha = htmlEntities[code]
32
- // str = str.replaceAll(code, cha);
33
- //}
34
- //return str
35
19
  return he.decode(str);
36
20
  }
37
21
 
@@ -40,15 +24,10 @@ export function decodeHtmlEntities(str:string) {
40
24
  * @returns 转换后的字符串
41
25
  */
42
26
  export function encodeHtmlEntities(str:string) {
43
- //for(let code in htmlEntities){
44
- // let cha = htmlEntities[code]
45
- // str = str.replaceAll(cha, code);
46
- //}
47
- //return str
48
27
  return he.encode(str);
49
28
  }
50
29
 
51
-
30
+ //#region LAM
52
31
  //token长度计算器
53
32
  //cl100k_base ChatGPT models, text-embedding-ada-002
54
33
  //p50k_base Code models, text-davinci-002, text-davinci-003
@@ -114,5 +93,5 @@ export function decodeTokenDavinci(arr:Uint32Array):string{
114
93
  initTikTokenEncoder();
115
94
  return textDecoder.decode(encoderDavinci?.decode(arr));
116
95
  }
117
-
96
+ //#endregion
118
97
  }
package/src/UtilFP.ts CHANGED
@@ -1,18 +1,21 @@
1
+ import { Keyable, LiteralCheck } from "./UtilInterfaces";
2
+ import { None } from "./UtilSymbol";
1
3
 
2
4
  /**常用函数式编程库 */
3
5
  export namespace UtilFP {
4
6
 
5
7
  /**柯里化函数类型 */
6
- type CurryFunc<T, PrevArgs extends unknown[] = []> = T extends (...args: infer Args) => infer Result
7
- ? Args extends [infer Arg, ...infer RestArgs]
8
- ? RestArgs extends []
9
- ? (...args: [...PrevArgs, Arg]) => Result
10
- : (...args: [...PrevArgs, Arg]) => CurryFunc<(...rest:RestArgs) => Result>
11
- & CurryFunc<(...args: RestArgs) => Result, [...PrevArgs, Arg]>
12
- : Args extends []
13
- ? () => Result
14
- : "CurryFunc错误 可选无法被识别" & Error
15
- : never;
8
+ type CurryFunc<T, PrevArgs extends unknown[] = []> =
9
+ T extends (...args: infer Args) => infer Result
10
+ ? Args extends [infer Arg, ...infer RestArgs]
11
+ ? RestArgs extends []
12
+ ? ((...args: [...PrevArgs, Arg]) => Result)
13
+ : ((...args: [...PrevArgs, Arg]) => CurryFunc<(...rest:RestArgs) => Result>)
14
+ & (CurryFunc<(...args: RestArgs) => Result, [...PrevArgs, Arg]>)
15
+ : Args extends []
16
+ ? () => Result
17
+ : "CurryFunc错误 默认参数可选无法被识别" & Error
18
+ : "CurryFunc错误 传入的并非函数" & Error;
16
19
 
17
20
  /**柯里化转换
18
21
  * @param {T} fn - 将要转换的函数
@@ -76,15 +79,88 @@ export function pipe<T>(input: T, ...fs: ((arg: T) => T)[]): T {
76
79
  }
77
80
 
78
81
 
79
- /**将一个字段加入一个对象中,返回新类型 */
80
- export function bindTo<K extends string, T, B extends {} = {}>
81
- (key:K,value:T,base?:B): B & Record<K,T>{
82
- let out = base as any;
83
- out = out??{};
84
- out[key]=value;
85
- return out;
82
+ /**将一个字段加入一个对象中, 返回新类型 */
83
+ //#region bind重载
84
+ /**绑定一个键和一个值到一个基础对象上, 并返回一个新的对象
85
+ * 新的对象包含了基础对象的所有属性, 以及一个新的属性,
86
+ * 这个新的属性的键是`key`, 值是`value`
87
+ * @template K - 要添加到对象的键的类型 必须为字面量
88
+ * @template V - 要添加到对象的值的类型
89
+ * @param key - 要添加到对象的键 必须为字面量
90
+ * @param value - 要添加到对象的值
91
+ * @returns 一个函数, 这个函数接受一个基础对象,
92
+ * 然后返回一个新的对象新的对象包含了基础对象的所有属性,
93
+ * 以及一个新的属性, 这个新的属性的键是`key`, 值是`value`
94
+ */
95
+ export function bind<K extends Keyable, V>
96
+ (key: LiteralCheck<K>,value: V): <B extends {}>
97
+ (base?: B) => keyof B extends K
98
+ ? "Base中已有对应键"&Error
99
+ : {[P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;};
100
+ /**绑定一个键到一个基础对象上,
101
+ * 并返回一个新的对象新的对象包含了基础对象的所有属性,
102
+ * 以及一个新的属性, 这个新的属性的键是`key`, 值是基础对象
103
+ * @template K - 要添加到对象的键的类型 必须为字面量
104
+ * @param key - 要添加到对象的键 必须为字面量
105
+ * @returns 一个函数, 这个函数接受一个基础对象,
106
+ * 然后返回一个新的对象新的对象包含了基础对象的所有属性,
107
+ * 以及一个新的属性, 这个新的属性的键是`key`, 值是基础对象
108
+ */
109
+ export function bind<K extends Keyable>
110
+ (key: LiteralCheck<K>): <B extends {}>
111
+ (base?: B) => { [P in K]: B };
112
+ /**绑定一个键和一个值到一个基础对象上, 并返回一个新的对象
113
+ * 新的对象包含了基础对象的所有属性, 以及一个新的属性,
114
+ * 这个新的属性的键是`key`, 值是`value`
115
+ * @template K - 要添加到对象的键的类型 必须为字面量
116
+ * @template V - 要添加到对象的值的类型
117
+ * @template B - 基础对象的类型
118
+ * @param key - 要添加到对象的键 必须为字面量
119
+ * @param value - 要添加到对象的值
120
+ * @param base - 基础对象
121
+ * @returns 完成绑定的基础对象
122
+ */
123
+ export function bind<K extends Keyable, V, B extends {}>
124
+ (key: LiteralCheck<K>,value: V, base:B):keyof B extends K
125
+ ? "Base中已有对应键"&Error
126
+ : {[P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;};
127
+ //#endregion
128
+ export function bind
129
+ <K extends Keyable, V, B>(key: LiteralCheck<K>, value?: V, base?:B){
130
+ if(base !== undefined)
131
+ return { ...base, [key as Keyable]: value };
132
+ if(value ===undefined)
133
+ return <B>(base?: B) =>
134
+ ({[key as Keyable]:base});
135
+
136
+ return <B extends {}>
137
+ (base?: B):{
138
+ [P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;
139
+ } => base !== undefined
140
+ ? { ...base, [key as Keyable]: value }
141
+ : ({ [key as Keyable]: value } as any);
86
142
  }
87
143
 
144
+ /**创建一个对对象的每个属性进行映射的函数
145
+ * @param func - 映射函数, 接受一个属性值和它的键, 返回一个新的属性值
146
+ * @returns 一个函数, 这个函数接受一个对象, 然后返回一个新的对象新的对象的每个属性都是原始对象的属性经过映射函数处理后的结果
147
+ */
148
+ export function map<VAL, OUT, KEY extends symbol|string = string>
149
+ (func:(input:VAL,k:KEY)=>OUT):
150
+ <OM extends Record<KEY,VAL>>
151
+ (input:OM)=>keyof OM extends KEY
152
+ ? {[P in keyof OM]:OUT}
153
+ : "map函数传入的键类型无法处理此对象"&Error{
154
+ return (input) => {
155
+ return Reflect
156
+ .ownKeys(input as Record<Keyable,unknown>)
157
+ .reduce((sum,curr)=>({ ...sum,
158
+ [curr] : func((input as any)[curr],curr as any)
159
+ }),{}) as any;
160
+ };
161
+ }
162
+
163
+
88
164
  /**
89
165
  let asd = bindTo("sss",123,{abc:223});//?
90
166
  let sumvoid = ()=>10;
@@ -99,5 +175,11 @@ let sumz = sumCu(1,"b",3)(false);//?
99
175
  console.log(suma(2,true));
100
176
  console.log(sumb(true));
101
177
  console.log(sumc("s",3,false));
102
- */
178
+
179
+ Reflect.ownKeys({[1]:1,[None]:2});//?
180
+ let as = "ssa" as string;//?
181
+ let asv = {"s":1};//?
182
+ let a = map((v:number,k)=>v*21);//?
183
+ let b = a({["ss"]:1})//?
184
+ */
103
185
  }
@@ -1,9 +1,9 @@
1
- import { FfmpegCommand, FfprobeData } from "fluent-ffmpeg";
2
- import * as fluentFfmpeg from "fluent-ffmpeg";
1
+ import { FfprobeData } from "fluent-ffmpeg";
2
+ import fluentFfmpeg from "fluent-ffmpeg";
3
3
  import * as path from "path";
4
4
  import * as fs from "fs";
5
- import { SList, SStream } from "@src/UtilClass";
6
5
  import { SLogger } from "@src/UtilLogger";
6
+ import { Stream } from "./UtilClass";
7
7
 
8
8
  /**输入输出路径映射
9
9
  * 输入路径:输入路径
@@ -13,8 +13,7 @@ export type IOMap = { [key: string]: string };
13
13
  /**ffmpeg工具类
14
14
  */
15
15
  class SFfmpegTool {
16
- /**静态构造函数
17
- */
16
+ /**静态构造函数 */
18
17
  static init() {
19
18
  let ffmpegPath = process.env.FFMPEG_PATH;
20
19
  if(ffmpegPath!=null){
@@ -22,8 +21,7 @@ class SFfmpegTool {
22
21
  SFfmpegTool.setFfmpegPath(exepath);
23
22
  }
24
23
  }
25
- /**设置ffmpeg路径
26
- */
24
+ /**设置ffmpeg路径 */
27
25
  static setFfmpegPath(ffmpegPath: string) {
28
26
  fluentFfmpeg.setFfmpegPath(ffmpegPath);
29
27
  }
@@ -168,13 +166,12 @@ class SFfmpegTool {
168
166
  * @param cpCount - 并发数
169
167
  */
170
168
  static async wav2oggMP(ioMap: IOMap, quality = 10, cpCount = 16) {
171
- await new SList(Object.entries(ioMap))
172
- .toSStream(cpCount)
169
+ await new Stream(Object.entries(ioMap))
173
170
  .map(async ([inPath, outPath]) => {
174
171
  SLogger.info("SFfmpegTool.wav2oggMP 正在处理:" + outPath);
175
172
  await SFfmpegTool.wav2ogg(inPath, outPath, quality);
176
173
  })
177
- .appendOperations();
174
+ .append();
178
175
  }
179
176
  /**flac转ogg多线程
180
177
  * @param ioMap - 输入输出路径映射
@@ -186,13 +183,12 @@ class SFfmpegTool {
186
183
  quality: number = 10,
187
184
  cpCount: number = 16
188
185
  ) {
189
- await new SList(Object.entries(ioMap))
190
- .toSStream(cpCount)
186
+ await new Stream(Object.entries(ioMap))
191
187
  .map(async ([inPath, outPath]) => {
192
188
  SLogger.info("SFfmpegTool.flac2oggMP 正在处理:" + outPath);
193
189
  await SFfmpegTool.flac2ogg(inPath, outPath, quality);
194
190
  })
195
- .appendOperations();
191
+ .append();
196
192
  }
197
193
  /**删除静音多线程
198
194
  * @param ioMap - 输入输出路径映射
@@ -205,13 +201,12 @@ class SFfmpegTool {
205
201
  silence: number = 0.2,
206
202
  cpCount: number = 16
207
203
  ) {
208
- await new SList(Object.entries(ioMap))
209
- .toSStream(cpCount)
204
+ await new Stream(Object.entries(ioMap))
210
205
  .map(async ([inPath, outPath]) => {
211
206
  SLogger.info("SFfmpegTool.trimSilenceMP 正在处理:" + outPath);
212
207
  await SFfmpegTool.trimSilence(inPath, outPath, threshold, silence);
213
208
  })
214
- .appendOperations();
209
+ .append();
215
210
  }
216
211
 
217
212
  /**重采样多线程
@@ -220,13 +215,12 @@ class SFfmpegTool {
220
215
  * @param cpCount - 并发数
221
216
  */
222
217
  static async resampleMP(ioMap: IOMap, rate: number = 22050, cpCount: number = 16) {
223
- await new SList(Object.entries(ioMap))
224
- .toSStream(cpCount)
218
+ await new Stream(Object.entries(ioMap))
225
219
  .map(async ([inPath, outPath]) => {
226
220
  SLogger.info("SFfmpegTool.resampleMP 正在处理:" + outPath);
227
221
  await SFfmpegTool.resample(inPath, outPath, rate);
228
222
  })
229
- .appendOperations();
223
+ .append();
230
224
  }
231
225
  }
232
226
  SFfmpegTool.init();
@@ -3,7 +3,7 @@ import { AnyFunc, ComposedClass, ComposedMixinable, ExtractOutcome, IJData, JObj
3
3
  import * as cp from "child_process";
4
4
  import { SLogger } from "@src/UtilLogger";
5
5
  import { Completed, Failed, FailedLike, None, StatusSymbol, Success, SuccessLike, Terminated, Timeout } from "./UtilSymbol";
6
- import { DeferAsync, LogTimeAsync } from "./UtilDecorators";
6
+ import { Catch, DeferAsync, LogTimeAsync } from "./UtilDecorators";
7
7
 
8
8
 
9
9
  type SuccessOut<T> = Outcome<Success,T>;
@@ -434,15 +434,13 @@ static matchProc<
434
434
  if (typeof t === 'string' || typeof t === 'number' || typeof t === 'symbol'){
435
435
  if ((procObj as any)[t])
436
436
  return (procObj as any)[t](t);
437
- SLogger.fatal(`matchProc 传入了一个预料之外的值: `,t);
438
- throw None;
439
- }
440
- else{
441
- if ((procObj as any)[t.status])
442
- return (procObj as any)[t.status](t.status,(t as any).result);
443
- SLogger.fatal(`matchProc 传入了一个预料之外的值: `,t);
444
- throw None;
445
437
  }
438
+ else if ((procObj as any)[t.status])
439
+ return (procObj as any)[t.status](t.status,(t as any).result);
440
+
441
+ const err = new Error(`matchProc 传入了一个预料之外的值: ${String(t)}`);
442
+ SLogger.fatal(err);
443
+ throw err;
446
444
  }
447
445
 
448
446
  /**根据典型的成功或失败状态运行函数
@@ -481,7 +479,7 @@ static isFailed<T>
481
479
  /**是成功的 */
482
480
  static isSuccess<T>
483
481
  (tg:T):T extends Matchable<SuccessLike>
484
- ? true: MatchableFlag<T> extends Exclude<MatchableFlag<T>,SuccessLike>
482
+ ? true : MatchableFlag<T> extends Exclude<MatchableFlag<T>,SuccessLike>
485
483
  ? false : boolean{
486
484
  const test = (t:any)=>t === Success || t === Completed;
487
485
  if(tg!=null && typeof tg === 'object' && 'status' in tg)
@@ -504,6 +502,17 @@ static likeNone(t:unknown,strictLog=true):t is None{
504
502
  return t == null;
505
503
  }
506
504
 
505
+ /**验证一个值是否为空
506
+ * 为空则抛异
507
+ * @param t - 验证目标
508
+ * @param errLog - 异常信息
509
+ * @returns 排除None的原值
510
+ */
511
+ static expect<T>(t:T,errLog?:string):Exclude<T,None>{
512
+ if(t===None) throw new Error(errLog);
513
+ return t as Exclude<T,None>;
514
+ }
515
+
507
516
  /**验证一个变量的类型是否为 T
508
517
  * @template T - 验证类型
509
518
  * @param t - 验证目标
@@ -540,4 +549,15 @@ static isSafeNumber(num: unknown): boolean {
540
549
  return false;
541
550
  }
542
551
 
552
+ /**将一个字段加入一个对象中,将改变对象,返回新类型 */
553
+ static bindTo<K extends Keyable, V, B extends {} = {}>
554
+ (key: LiteralCheck<K>,value: V, base?:B):keyof B extends K
555
+ ? "Base中已有对应键"&Error
556
+ : {[P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;}{
557
+ let out = base as any;
558
+ out = out??{};
559
+ out[key]=value;
560
+ return out;
561
+ }
562
+
543
563
  }
@@ -45,6 +45,11 @@ export type LiteralCheck<L> =
45
45
  ProperSubset<Record<any,any>, L> |
46
46
  null | undefined;
47
47
 
48
+ /**返回将Mixin分配给Base的结果,相同字段时Mixin覆盖Base */
49
+ export type AssignObject<Base extends {}, Mixin extends {}> = {
50
+ [P in keyof Mixin | keyof Base]: P extends keyof Mixin ? Mixin[P] : P extends keyof Base ? Base[P] : never;
51
+ }
52
+
48
53
  /**转为可写的 */
49
54
  export type Writeable<T> = {
50
55
  -readonly [P in keyof T]: T[P]
package/src/UtilLogger.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as path from 'path';
2
2
  import * as winston from 'winston';
3
- import * as DailyRotateFile from 'winston-daily-rotate-file';
3
+ import DailyRotateFile from 'winston-daily-rotate-file';
4
4
  import {inspect} from 'util';
5
5
 
6
6
 
@@ -253,17 +253,16 @@ export class SLogger{
253
253
  let acc = 0;
254
254
  const maxAcc = 3;
255
255
 
256
- let concat = function(num:number,sep:string,
257
- formatText:string,resultText:string):void{
258
- let hasResult = result.length>0;
259
- let need = (hasResult || num>0) && (acc < maxAcc);
260
- if(need){
261
- if(result.length>0) result+=sep;
262
- if(format.length>0) format+=sep;
263
- result += resultText;
264
- format += formatText;
265
- acc++;
266
- }
256
+ const concat = (num:number,sep:string,
257
+ formatText:string,resultText:string): void => {
258
+ const hasResult = result.length>0;
259
+ const need = (hasResult || num>0) && (acc < maxAcc);
260
+ if(!need) return;
261
+ if(result.length>0) result+=sep;
262
+ if(format.length>0) format+=sep;
263
+ result += resultText;
264
+ format += formatText;
265
+ acc++;
267
266
  }
268
267
  concat(Days,':','dd',
269
268
  `${Days.toString()}`);
@@ -285,7 +284,7 @@ export class SLogger{
285
284
  }
286
285
 
287
286
  if(level!==null)
288
- this.log(level,flag+": "+out);
287
+ this.log(level,`${flag}: ${out}`);
289
288
  delete SLogger.timeTable[flag];
290
289
  return out;
291
290
  }
@@ -301,7 +300,7 @@ export class SLogger{
301
300
  }
302
301
  /**让名称为default的logger 产生一条对应等级的log 返回自身
303
302
  * @param level - log等级
304
- * @param messages - log消息
303
+ * @param messages - log消息
305
304
  * @returns 自身
306
305
  */
307
306
  static log(level: LogLevel, ...messages:Array<any>):SLogger{
package/tsconfig.json CHANGED
@@ -3,7 +3,9 @@
3
3
  "allowJs": true,
4
4
  "strict": true,
5
5
  "target": "ES2022",
6
- "module": "commonjs",
6
+ "module": "CommonJS",
7
+ "moduleResolution": "node",
8
+ "esModuleInterop": true,
7
9
  "outDir": "./dist",
8
10
  "declaration": true,
9
11
  "baseUrl": ".",
@@ -1,4 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$ref": "schemas.json#/definitions/TestType1"
4
- }
@@ -1,4 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$ref": "schemas.json#/definitions/TestType2"
4
- }
@@ -1,35 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "definitions": {
4
- "TestType2": {
5
- "type": "object",
6
- "properties": {
7
- "a": {
8
- "type": "string"
9
- },
10
- "b": {
11
- "type": "number"
12
- }
13
- },
14
- "required": [
15
- "a",
16
- "b"
17
- ]
18
- },
19
- "TestType1": {
20
- "type": "object",
21
- "properties": {
22
- "a": {
23
- "type": "string"
24
- },
25
- "b": {
26
- "type": "number"
27
- }
28
- },
29
- "required": [
30
- "a",
31
- "b"
32
- ]
33
- }
34
- }
35
- }