@zwa73/utils 1.0.134 → 1.0.135

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/UtilCom.d.ts CHANGED
@@ -1,5 +1,22 @@
1
- import { JObject, ReqVerifyFn } from "./UtilInterfaces";
1
+ import { AnyString, JObject, ReqVerifyFn } from "./UtilInterfaces";
2
2
  import { RepeatPromiseOpt } from "./UtilFunctions";
3
+ export type ComPostOption = {
4
+ /**请求域名 */
5
+ hostname: string;
6
+ /**请求路径 */
7
+ path: string;
8
+ /**方式 post为 POST */
9
+ method: 'POST';
10
+ /**端口 */
11
+ port?: number;
12
+ /**请求头 */
13
+ headers?: {
14
+ /**内容类型 */
15
+ 'Content-Type'?: 'application/json' | AnyString;
16
+ /**内容长度 一般无需填写 应为buffer长度而非字符串长度 */
17
+ 'Content-Length'?: number;
18
+ };
19
+ };
3
20
  type RepeatPostOpt = Partial<{
4
21
  /**httppost 超时中断时间限制 */
5
22
  postTimeLimit?: number;
@@ -13,7 +30,7 @@ export declare namespace UtilCom {
13
30
  * @param timeLimit - 超时时间/秒 最小为10秒
14
31
  * @returns 结果 null 为未能成功接收
15
32
  */
16
- function shttpsPost(json: JObject, options: Object, timeLimit?: number): Promise<JObject | null>;
33
+ function shttpsPost(json: JObject, options: ComPostOption, timeLimit?: number): Promise<JObject | null>;
17
34
  /**发送一个 http POST请求并接受数据
18
35
  * @async
19
36
  * @param json - 数据对象
@@ -21,7 +38,7 @@ export declare namespace UtilCom {
21
38
  * @param timeLimit - 超时时间/秒 最小为10秒
22
39
  * @returns 结果 null 为未能成功接收
23
40
  */
24
- function shttpPost(json: JObject, options: Object, timeLimit?: number): Promise<JObject | null>;
41
+ function shttpPost(json: JObject, options: ComPostOption, timeLimit?: number): Promise<JObject | null>;
25
42
  /**重复一个 https POST请求并接受数据
26
43
  * @async
27
44
  * @param json - 数据对象
@@ -34,7 +51,7 @@ export declare namespace UtilCom {
34
51
  * @param opt.try_delay - 重试间隔 秒 默认0
35
52
  * @returns 结果 null 为未能成功接收
36
53
  */
37
- function shttpsRepeatPost(json: JObject, options: Object, verifyFn?: ReqVerifyFn<JObject | null>, opt?: RepeatPostOpt): Promise<JObject | null>;
54
+ function shttpsRepeatPost(json: JObject, options: ComPostOption, verifyFn?: ReqVerifyFn<JObject | null>, opt?: RepeatPostOpt): Promise<JObject | null>;
38
55
  /**重复一个 http POST请求并接受数据
39
56
  * Object ()
40
57
  * @async
@@ -48,6 +65,6 @@ export declare namespace UtilCom {
48
65
  * @param opt.try_delay - 重试间隔 秒 默认0
49
66
  * @returns 结果 null 为未能成功接收
50
67
  */
51
- function shttpRepeatPost(json: JObject, options: Object, verifyFn?: ReqVerifyFn<JObject | null>, opt?: RepeatPostOpt): Promise<JObject | null>;
68
+ function shttpRepeatPost(json: JObject, options: ComPostOption, verifyFn?: ReqVerifyFn<JObject | null>, opt?: RepeatPostOpt): Promise<JObject | null>;
52
69
  }
53
70
  export {};
package/dist/UtilCom.js CHANGED
@@ -73,7 +73,7 @@ var UtilCom;
73
73
  return;
74
74
  }
75
75
  try {
76
- let obj = JSON.parse(resdata);
76
+ const obj = JSON.parse(resdata);
77
77
  UtilLogger_1.SLogger.http(funcName + " 接受信息:", UtilFunctions_1.UtilFunc.stringifyJToken(obj));
78
78
  resolve(obj);
79
79
  return;
package/dist/UtilFP.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Keyable, Literal, Matchable, MatchableFlag, ProperSubsetCheck } from "./UtilInterfaces";
1
+ import { AnyRecord, Keyable, Literal, Matchable, MatchableFlag, ProperSubsetCheck } from "./UtilInterfaces";
2
2
  import { FailedLike } from "./UtilSymbol";
3
3
  /**常用函数式编程库 */
4
4
  export declare namespace UtilFP {
@@ -76,7 +76,7 @@ export declare namespace UtilFP {
76
76
  * 然后返回一个新的对象新的对象包含了基础对象的所有属性,
77
77
  * 以及一个新的属性, 这个新的属性的键是`key`, 值是`value`
78
78
  */
79
- export function bind<K extends Keyable, V>(key: Literal<K>, value: V): <B extends {}>(base?: B) => keyof B extends K ? "Base中已有对应键" & Error : {
79
+ export function bind<K extends Keyable, V>(key: Literal<K>, value: V): <B extends AnyRecord>(base?: B) => keyof B extends K ? "Base中已有对应键" & Error : {
80
80
  [P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;
81
81
  };
82
82
  /**绑定一个键到一个基础对象上,
@@ -88,7 +88,7 @@ export declare namespace UtilFP {
88
88
  * 然后返回一个新的对象新的对象包含了基础对象的所有属性,
89
89
  * 以及一个新的属性, 这个新的属性的键是`key`, 值是基础对象
90
90
  */
91
- export function bind<K extends Keyable>(key: Literal<K>): <B extends {}>(base?: B) => {
91
+ export function bind<K extends Keyable>(key: Literal<K>): <B extends AnyRecord>(base?: B) => {
92
92
  [P in K]: B;
93
93
  };
94
94
  /**绑定一个键和一个值到一个基础对象上, 并返回一个新的对象
@@ -102,7 +102,7 @@ export declare namespace UtilFP {
102
102
  * @param base - 基础对象
103
103
  * @returns 完成绑定的基础对象
104
104
  */
105
- export function bind<K extends Keyable, V, B extends {}>(key: Literal<K>, value: V, base: B): keyof B extends K ? "Base中已有对应键" & Error : {
105
+ export function bind<K extends Keyable, V, B extends AnyRecord>(key: Literal<K>, value: V, base: B): keyof B extends K ? "Base中已有对应键" & Error : {
106
106
  [P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;
107
107
  };
108
108
  /**创建一个对对象的每个属性进行映射的函数
@@ -29,6 +29,15 @@ type LoadJsonFileOpt<T> = Partial<{
29
29
  default: T;
30
30
  /**以json5模式加载 略慢 默认false */
31
31
  json5: boolean;
32
+ /**不自动修改扩展名为json */
33
+ forceExt: boolean;
34
+ }>;
35
+ /**json文件写入选项 */
36
+ type WriteJsonFileOpt = Partial<{
37
+ /**使用紧凑风格 */
38
+ compress: boolean;
39
+ /**不自动修改扩展名为json */
40
+ forceExt: boolean;
32
41
  }>;
33
42
  /**文件工具 */
34
43
  export declare namespace UtilFT {
@@ -81,8 +90,9 @@ export declare namespace UtilFT {
81
90
  /**加载json文件 同步
82
91
  * @param filePath - 文件路径
83
92
  * @param opt - 可选参数
84
- * @param opt.default - 默认值
85
- * @param opt.json5 - json5模式
93
+ * @param opt.default - 默认值
94
+ * @param opt.json5 - json5模式
95
+ * @param opt.forceExt - 不自动修改扩展名为json
86
96
  * @returns 加载完成的对象或默认值
87
97
  */
88
98
  function loadJSONFileSync<T extends JToken>(filePath: string, opt: LoadJsonFileOpt<T>): T;
@@ -96,8 +106,9 @@ export declare namespace UtilFT {
96
106
  * @async
97
107
  * @param filePath - 文件路径
98
108
  * @param opt - 可选参数
99
- * @param opt.default - 默认值
100
- * @param opt.json5 - json5模式
109
+ * @param opt.default - 默认值
110
+ * @param opt.json5 - json5模式
111
+ * @param opt.forceExt - 不自动修改扩展名为json
101
112
  * @returns 加载完成的对象或默认值
102
113
  */
103
114
  function loadJSONFile<T extends JToken>(filePath: string, opt: LoadJsonFileOpt<T>): Promise<T>;
@@ -106,8 +117,11 @@ export declare namespace UtilFT {
106
117
  * @async
107
118
  * @param filePath - 文件路径
108
119
  * @param token - 所要写入的JToken
120
+ * @param opt - 可选参数
121
+ * @param opt.compress - 使用紧凑风格
122
+ * @param opt.forceExt - 不自动修改扩展名为json
109
123
  */
110
- function writeJSONFile(filePath: string, token: JToken): Promise<void>;
124
+ function writeJSONFile(filePath: string, token: JToken, opt?: WriteJsonFileOpt): Promise<void>;
111
125
  /**保证路径为某个风格
112
126
  * @param filePath - 输入路径
113
127
  * @param style - 目标风格 undefined 时不改变
@@ -142,12 +142,11 @@ var UtilFT;
142
142
  }
143
143
  UtilFT.ensurePathExistsSync = ensurePathExistsSync;
144
144
  function loadJSONFileSync(filePath, opt) {
145
- if (pathe_1.default.extname(filePath) !== '.json')
145
+ if (opt?.forceExt !== true && pathe_1.default.extname(filePath) !== '.json')
146
146
  filePath += '.json';
147
- let str = "";
148
- // 判断文件路径是否存在
149
- if (pathExistsSync(filePath))
150
- str = fs.readFileSync(filePath, "utf-8");
147
+ const str = pathExistsSync(filePath)
148
+ ? fs.readFileSync(filePath, "utf-8")
149
+ : "";
151
150
  // 如果不存在则返回默认值
152
151
  if (str == "" || str == null) {
153
152
  if (opt?.default !== undefined)
@@ -160,12 +159,11 @@ var UtilFT;
160
159
  }
161
160
  UtilFT.loadJSONFileSync = loadJSONFileSync;
162
161
  async function loadJSONFile(filePath, opt) {
163
- if (pathe_1.default.extname(filePath) !== '.json')
162
+ if (opt?.forceExt !== true && pathe_1.default.extname(filePath) !== '.json')
164
163
  filePath += '.json';
165
- let str = "";
166
- // 判断文件路径是否存在
167
- if (await pathExists(filePath))
168
- str = await fs.promises.readFile(filePath, "utf-8");
164
+ const str = (await pathExists(filePath))
165
+ ? await fs.promises.readFile(filePath, "utf-8")
166
+ : "";
169
167
  // 如果不存在则返回默认值
170
168
  if (str == "" || str == null) {
171
169
  if (opt?.default !== undefined)
@@ -182,10 +180,13 @@ var UtilFT;
182
180
  * @async
183
181
  * @param filePath - 文件路径
184
182
  * @param token - 所要写入的JToken
183
+ * @param opt - 可选参数
184
+ * @param opt.compress - 使用紧凑风格
185
+ * @param opt.forceExt - 不自动修改扩展名为json
185
186
  */
186
- async function writeJSONFile(filePath, token) {
187
- const str = UtilFunctions_1.UtilFunc.stringifyJToken(token);
188
- if (pathe_1.default.extname(filePath) !== '.json')
187
+ async function writeJSONFile(filePath, token, opt) {
188
+ const str = UtilFunctions_1.UtilFunc.stringifyJToken(token, opt);
189
+ if (opt?.forceExt !== true && pathe_1.default.extname(filePath) !== '.json')
189
190
  filePath += '.json';
190
191
  // 判断文件路径是否存在 不存在则创建
191
192
  if (!(await pathExists(filePath)))
@@ -1,4 +1,4 @@
1
- import { AnyFunc, ComposedClass, ComposedMixinable, ComposedRefMixinable, ExtractOutcome, IJData, JObject, JToken, Keyable, Literal, Matchable, MatchableFlag, Mixinable, Outcome, ReqVerifyFn, ProperSubsetCheck, RefMixinable, UnionToIntersection, Await } from "./UtilInterfaces";
1
+ import { AnyFunc, ComposedClass, ComposedMixinable, ComposedRefMixinable, ExtractOutcome, IJData, JObject, JToken, Keyable, Literal, Matchable, MatchableFlag, Mixinable, Outcome, ReqVerifyFn, ProperSubsetCheck, RefMixinable, UnionToIntersection, Await, AnyRecord } from "./UtilInterfaces";
2
2
  import { LogLevel } from "./UtilLogger";
3
3
  import { Failed, FailedLike, None, StatusSymbol, Success, SuccessLike, Timeout } from "./UtilSymbol";
4
4
  declare const HashMethodList: readonly ["md5", "sha1", "sha256", "sha512", "sha3", "blake2", "blake3"];
@@ -8,6 +8,13 @@ type ExecOpt = Partial<{
8
8
  outlvl: LogLevel;
9
9
  errlvl: LogLevel;
10
10
  }>;
11
+ /**序列化选项 */
12
+ type StringifyOpt = Partial<{
13
+ /**使用紧凑风格 */
14
+ compress: boolean;
15
+ /**插入的空格 数字为空格数量 默认为制表符\t */
16
+ space: string | number | null | undefined;
17
+ }>;
11
18
  /**Promise重试选项 */
12
19
  export type RepeatPromiseOpt = Partial<{
13
20
  /**重试次数 默认3*/
@@ -34,7 +41,7 @@ export declare class UtilFunc {
34
41
  * @param defaultVal - 默认值
35
42
  * @returns 最终值
36
43
  */
37
- static initField<T extends object, K extends keyof T>(obj: T, field: K, defaultVal: T[K]): T[K];
44
+ static initField<T extends AnyRecord, K extends keyof T>(obj: T, field: K, defaultVal: T[K]): T[K];
38
45
  /**初始化一个数据对象
39
46
  * @param obj - 目标对象
40
47
  * @param checkObj - 用于检测的对象 在对应key缺失时赋予对应值 如果值为函数, 则赋予执行结果 如果结果为 undefined 则不赋值
@@ -107,26 +114,28 @@ export declare class UtilFunc {
107
114
  * @param fields - 需要混入的字段
108
115
  * @returns 混合完成的类
109
116
  */
110
- 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>;
117
+ static composeClassPart<Base extends AnyRecord, Mixin extends AnyRecord, Field extends keyof Mixin>(base: Base, mixin: Mixin, key: string, ...fields: Field[]): ComposedClass<Base, Mixin, typeof key, Field>;
111
118
  /**根据 MIXIN_FIELDS 自动混入
112
119
  * @deprecated 非必要情况下, 对class定义请使用 composeRefMixinable
113
120
  */
114
- static composeMixinable<Base extends object, Mixins extends Mixinable<any>[]>(base: Base, ...mixins: Mixins): ComposedMixinable<Base, Mixins>;
121
+ static composeMixinable<Base extends AnyRecord, Mixins extends Mixinable<any>[]>(base: Base, ...mixins: Mixins): ComposedMixinable<Base, Mixins>;
115
122
  /**根据 MIXIN_FIELDS 自动混入 */
116
- static composeRefMixinable<Base extends object, Mixins extends RefMixinable<any, unknown>[]>(base: Base, ...mixins: Mixins): ComposedRefMixinable<Base, Mixins>;
123
+ static composeRefMixinable<Base extends AnyRecord, Mixins extends RefMixinable<any, unknown>[]>(base: Base, ...mixins: Mixins): ComposedRefMixinable<Base, Mixins>;
117
124
  /**对对象的每个属性应用映射函数,并返回一个新的对象。
118
125
  * @template T - 对象的类型
119
126
  * @param obj - 要处理的对象
120
127
  * @param mapper - 映射函数,接受一个值和一个键,返回一个新的值
121
128
  * @returns - 一个新的对象,它的属性是原对象的属性经过映射函数处理后的结果
122
129
  */
123
- static mapEntries<T extends object>(obj: T, mapper: (key: keyof T, value: T[keyof T]) => T[keyof T]): T;
130
+ static mapEntries<T extends AnyRecord>(obj: T, mapper: (key: keyof T, value: T[keyof T]) => T[keyof T]): T;
124
131
  /**将JToken转换为字符串
125
132
  * @param token - 待转换的Token
126
- * @param space - 插入的空格 数字为空格数量 默认为制表符\t
133
+ * @param opt - 可选参数
134
+ * @param opt.space - 插入的空格 数字为空格数量 默认为制表符\t
135
+ * @param opt.compress - 使用紧凑风格
127
136
  * @returns 转换完成的字符串
128
137
  */
129
- static stringifyJToken(token: JToken | IJData, space?: string | number | null | undefined): string;
138
+ static stringifyJToken(token: JToken | IJData, opt?: StringifyOpt): string;
130
139
  /**代办表 用于队列处理等待 */
131
140
  static pendingMap: Record<Keyable, AnyFunc[]>;
132
141
  /**队列处理
@@ -202,7 +211,7 @@ export declare class UtilFunc {
202
211
  */
203
212
  static isSafeNumber(num: unknown): boolean;
204
213
  /**将一个字段加入一个对象中,将改变对象,返回新类型 */
205
- static bindTo<K extends Keyable, V, B extends {} = {}>(key: Literal<K>, value: V, base?: B): keyof B extends K ? "Base中已有对应键" & Error : {
214
+ static bindTo<K extends Keyable, V, B extends AnyRecord = {}>(key: Literal<K>, value: V, base?: B): keyof B extends K ? "Base中已有对应键" & Error : {
206
215
  [P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;
207
216
  };
208
217
  /**移除多行字符串中每行开始的最小空格数。
@@ -377,13 +377,30 @@ class UtilFunc {
377
377
  }
378
378
  /**将JToken转换为字符串
379
379
  * @param token - 待转换的Token
380
- * @param space - 插入的空格 数字为空格数量 默认为制表符\t
380
+ * @param opt - 可选参数
381
+ * @param opt.space - 插入的空格 数字为空格数量 默认为制表符\t
382
+ * @param opt.compress - 使用紧凑风格
381
383
  * @returns 转换完成的字符串
382
384
  */
383
- static stringifyJToken(token, space = "\t") {
384
- if (space == null)
385
- space = undefined;
386
- return JSON.stringify(token, null, space);
385
+ static stringifyJToken(token, opt) {
386
+ opt ??= {};
387
+ let { compress, space } = opt;
388
+ space ??= "\t";
389
+ space = space === null ? undefined : space;
390
+ if (!compress)
391
+ return JSON.stringify(token, null, space);
392
+ const compressReplacer = (key, value) => {
393
+ if (Array.isArray(value) && value.every(item => typeof item === 'number' || typeof item === 'string' ||
394
+ typeof item === 'boolean' || item == null))
395
+ return `@@@${JSON.stringify(value)}@@@`;
396
+ const str = JSON.stringify(value);
397
+ if (str.length <= 100)
398
+ return `@@@${str}@@@`;
399
+ return value;
400
+ };
401
+ return JSON.stringify(token, compressReplacer, space)
402
+ .replace(/"@@@(.*?)@@@"/g, `$1`)
403
+ .replace(/\\([\\"])/g, '$1');
387
404
  }
388
405
  /**代办表 用于队列处理等待 */
389
406
  static pendingMap = {};
@@ -49,7 +49,7 @@ export type Literal<L> = ProperSubset<string, L> | ProperSubset<number, L> | Pro
49
49
  */
50
50
  export type LiteralCheck<L> = ProperSubsetCheck<string, L> extends "P" ? true : ProperSubsetCheck<number, L> extends "P" ? true : ProperSubsetCheck<boolean, L> extends "P" ? true : ProperSubsetCheck<symbol, L> extends "P" ? true : ProperSubsetCheck<any[], L> extends "P" ? true : ProperSubsetCheck<Record<any, any>, L> extends "P" ? true : L extends null | undefined ? true : false;
51
51
  /**返回将Mixin分配给Base的结果,相同字段时Mixin覆盖Base */
52
- export type AssignObject<Base extends {}, Mixin extends {}> = {
52
+ export type AssignObject<Base extends AnyRecord, Mixin extends AnyRecord> = {
53
53
  [P in keyof Mixin | keyof Base]: P extends keyof Mixin ? Mixin[P] : P extends keyof Base ? Base[P] : never;
54
54
  };
55
55
  /**转为可写的 */
@@ -138,8 +138,17 @@ export type ReflectionAble<Ctor, Constraint = {}> = {
138
138
  };
139
139
  /**可反射的 且 构造函数是可混入的类
140
140
  * @template Ctor - 构造器类型
141
- * @template Instance - 实例类型
141
+ * @template Instance - 实例类型 如果采用了内部混入, 那么填入对外实际暴露的类型, 以支持混入多层字段
142
142
  * @template Constraint - 构造器约束
143
+ * @example
144
+ * export class MixinModule implements RefMixinable<typeof MixinModule,MixinModule>{
145
+ * static readonly MIXIN_FIELDS = [
146
+ * 'func_a',
147
+ * 'field_b'
148
+ * ] as const;
149
+ * static readonly MIXIN_KEY = '__mixinModule';
150
+ * CTOR = MixinModule;
151
+ * }
143
152
  */
144
153
  export type RefMixinable<Ctor, Instance, Constraint = {}> = ReflectionAble<Ctor, Mixinable<Instance> & Constraint>;
145
154
  /**自动组合可混入的类
@@ -194,4 +203,12 @@ export type NeedInit = {
194
203
  };
195
204
  /**可选的record */
196
205
  export type PRecord<K extends Keyable, V> = Partial<Record<K, V>>;
206
+ /**任何Record */
207
+ export type AnyRecord = Record<Keyable, any>;
208
+ /**注释元组
209
+ * @template T - 提供注释的类型, 索引需从0开始
210
+ */
211
+ export type AnnotableTuple<T extends {
212
+ [K: number]: unknown;
213
+ }, Tuple extends unknown[] = []> = unknown extends T[Tuple['length']] ? T & Tuple : AnnotableTuple<T, [...Tuple, T[Tuple['length']]]>;
197
214
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zwa73/utils",
3
- "version": "1.0.134",
3
+ "version": "1.0.135",
4
4
  "description": "my utils",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/UtilCom.ts CHANGED
@@ -1,10 +1,26 @@
1
- import { JObject, ReqVerifyFn } from "@src/UtilInterfaces";
1
+ import { AnyString, JObject, ReqVerifyFn } from "@src/UtilInterfaces";
2
2
  import * as https from 'https';
3
3
  import * as http from 'http';
4
4
  import { SLogger } from "@src/UtilLogger";
5
5
  import { RepeatPromiseOpt, UtilFunc } from "@src/UtilFunctions";
6
6
 
7
-
7
+ export type ComPostOption = {
8
+ /**请求域名 */
9
+ hostname: string;
10
+ /**请求路径 */
11
+ path: string;
12
+ /**方式 post为 POST */
13
+ method: 'POST';
14
+ /**端口 */
15
+ port?:number;
16
+ /**请求头 */
17
+ headers?: {
18
+ /**内容类型 */
19
+ 'Content-Type'?: 'application/json'|AnyString;
20
+ /**内容长度 一般无需填写 应为buffer长度而非字符串长度 */
21
+ 'Content-Length'?: number;
22
+ }
23
+ }
8
24
 
9
25
  type RepeatPostOpt = Partial<{
10
26
  /**httppost 超时中断时间限制 */
@@ -21,7 +37,7 @@ export namespace UtilCom{
21
37
  * @param timeLimit - 超时时间/秒 最小为10秒
22
38
  * @returns 结果 null 为未能成功接收
23
39
  */
24
- function sPost(posttype:"http"|"https",json:JObject,options:Object,timeLimit?:number):Promise<JObject|null>{
40
+ function sPost(posttype:"http"|"https",json:JObject,options:ComPostOption,timeLimit?:number):Promise<JObject|null>{
25
41
  //转换为毫秒
26
42
  const hasTimeLimit = (timeLimit ? timeLimit>=10 : false );
27
43
  if(hasTimeLimit && timeLimit!=undefined) timeLimit*=1000;
@@ -60,7 +76,7 @@ function sPost(posttype:"http"|"https",json:JObject,options:Object,timeLimit?:nu
60
76
  return;
61
77
  }
62
78
  try{
63
- let obj = JSON.parse(resdata);
79
+ const obj = JSON.parse(resdata);
64
80
  SLogger.http(funcName+" 接受信息:",UtilFunc.stringifyJToken(obj));
65
81
  resolve(obj);
66
82
  return;
@@ -109,7 +125,7 @@ function sPost(posttype:"http"|"https",json:JObject,options:Object,timeLimit?:nu
109
125
  * @param timeLimit - 超时时间/秒 最小为10秒
110
126
  * @returns 结果 null 为未能成功接收
111
127
  */
112
- export function shttpsPost(json:JObject,options:Object,timeLimit?:number):Promise<JObject|null>{
128
+ export function shttpsPost(json:JObject,options:ComPostOption,timeLimit?:number):Promise<JObject|null>{
113
129
  return sPost("https",json,options,timeLimit);
114
130
  }
115
131
 
@@ -120,7 +136,7 @@ export function shttpsPost(json:JObject,options:Object,timeLimit?:number):Promis
120
136
  * @param timeLimit - 超时时间/秒 最小为10秒
121
137
  * @returns 结果 null 为未能成功接收
122
138
  */
123
- export function shttpPost(json:JObject,options:Object,timeLimit?:number):Promise<JObject|null>{
139
+ export function shttpPost(json:JObject,options:ComPostOption,timeLimit?:number):Promise<JObject|null>{
124
140
  return sPost("http",json,options,timeLimit);
125
141
  }
126
142
 
@@ -139,7 +155,7 @@ export function shttpPost(json:JObject,options:Object,timeLimit?:number):Promise
139
155
  * @param opt.try_delay - 重试间隔 秒 默认0
140
156
  * @returns 结果 null 为未能成功接收
141
157
  */
142
- async function sRepeatPost(posttype:"http"|"https",json:JObject,options:Object,verifyFn?:ReqVerifyFn<JObject|null>,opt:RepeatPostOpt={}):Promise<JObject|null>{
158
+ async function sRepeatPost(posttype:"http"|"https",json:JObject,options:ComPostOption,verifyFn?:ReqVerifyFn<JObject|null>,opt:RepeatPostOpt={}):Promise<JObject|null>{
143
159
  opt.count = opt.count??3;
144
160
  opt.tryInterval = opt.tryInterval??180;
145
161
  opt.tryDelay = opt.tryDelay??1;
@@ -161,7 +177,7 @@ async function sRepeatPost(posttype:"http"|"https",json:JObject,options:Object,v
161
177
  * @param opt.try_delay - 重试间隔 秒 默认0
162
178
  * @returns 结果 null 为未能成功接收
163
179
  */
164
- export function shttpsRepeatPost(json:JObject,options:Object,verifyFn?:ReqVerifyFn<JObject|null>,opt?:RepeatPostOpt):Promise<JObject|null>{
180
+ export function shttpsRepeatPost(json:JObject,options:ComPostOption,verifyFn?:ReqVerifyFn<JObject|null>,opt?:RepeatPostOpt):Promise<JObject|null>{
165
181
  return sRepeatPost("https",json,options,verifyFn,opt);
166
182
  }
167
183
 
@@ -178,7 +194,7 @@ export function shttpsRepeatPost(json:JObject,options:Object,verifyFn?:ReqVerify
178
194
  * @param opt.try_delay - 重试间隔 秒 默认0
179
195
  * @returns 结果 null 为未能成功接收
180
196
  */
181
- export function shttpRepeatPost(json:JObject,options:Object,verifyFn?:ReqVerifyFn<JObject|null>,opt?:RepeatPostOpt):Promise<JObject|null>{
197
+ export function shttpRepeatPost(json:JObject,options:ComPostOption,verifyFn?:ReqVerifyFn<JObject|null>,opt?:RepeatPostOpt):Promise<JObject|null>{
182
198
  return sRepeatPost("http",json,options,verifyFn,opt);
183
199
  }
184
200
 
package/src/UtilFP.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { isFailed, likeNone } from "./QuickFunction";
2
- import { Keyable, Literal, Matchable, MatchableFlag, ProperSubset, ProperSubsetCheck } from "./UtilInterfaces";
2
+ import { AnyRecord, Keyable, Literal, Matchable, MatchableFlag, ProperSubset, ProperSubsetCheck } from "./UtilInterfaces";
3
3
  import { Failed, FailedLike, None } from "./UtilSymbol";
4
4
 
5
5
  /**常用函数式编程库 */
@@ -116,7 +116,7 @@ export function pipe<T>(input: T, ...fs: ((arg: T) => T)[]): T {
116
116
  * 以及一个新的属性, 这个新的属性的键是`key`, 值是`value`
117
117
  */
118
118
  export function bind<K extends Keyable, V>
119
- (key: Literal<K>,value: V): <B extends {}>
119
+ (key: Literal<K>,value: V): <B extends AnyRecord>
120
120
  (base?: B) => keyof B extends K
121
121
  ? "Base中已有对应键"&Error
122
122
  : {[P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;};
@@ -130,7 +130,7 @@ export function bind<K extends Keyable, V>
130
130
  * 以及一个新的属性, 这个新的属性的键是`key`, 值是基础对象
131
131
  */
132
132
  export function bind<K extends Keyable>
133
- (key: Literal<K>): <B extends {}>
133
+ (key: Literal<K>): <B extends AnyRecord>
134
134
  (base?: B) => { [P in K]: B };
135
135
  /**绑定一个键和一个值到一个基础对象上, 并返回一个新的对象
136
136
  * 新的对象包含了基础对象的所有属性, 以及一个新的属性,
@@ -143,7 +143,7 @@ export function bind<K extends Keyable>
143
143
  * @param base - 基础对象
144
144
  * @returns 完成绑定的基础对象
145
145
  */
146
- export function bind<K extends Keyable, V, B extends {}>
146
+ export function bind<K extends Keyable, V, B extends AnyRecord>
147
147
  (key: Literal<K>,value: V, base:B):keyof B extends K
148
148
  ? "Base中已有对应键"&Error
149
149
  : {[P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;};
@@ -156,7 +156,7 @@ export function bind
156
156
  return <B>(base?: B) =>
157
157
  ({[key as Keyable]:base});
158
158
 
159
- return <B extends {}>
159
+ return <B extends AnyRecord>
160
160
  (base?: B):{
161
161
  [P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;
162
162
  } => base !== undefined
@@ -40,8 +40,19 @@ type LoadJsonFileOpt<T> = Partial<{
40
40
  default:T;
41
41
  /**以json5模式加载 略慢 默认false */
42
42
  json5:boolean;
43
+ /**不自动修改扩展名为json */
44
+ forceExt:boolean;
43
45
  }>
44
46
 
47
+ /**json文件写入选项 */
48
+ type WriteJsonFileOpt = Partial<{
49
+ /**使用紧凑风格 */
50
+ compress:boolean;
51
+ /**不自动修改扩展名为json */
52
+ forceExt:boolean;
53
+ }>
54
+
55
+
45
56
  /**文件工具 */
46
57
  export namespace UtilFT{
47
58
 
@@ -157,19 +168,19 @@ export function loadJSONFileSync(filePath: string): JToken
157
168
  /**加载json文件 同步
158
169
  * @param filePath - 文件路径
159
170
  * @param opt - 可选参数
160
- * @param opt.default - 默认值
161
- * @param opt.json5 - json5模式
171
+ * @param opt.default - 默认值
172
+ * @param opt.json5 - json5模式
173
+ * @param opt.forceExt - 不自动修改扩展名为json
162
174
  * @returns 加载完成的对象或默认值
163
175
  */
164
176
  export function loadJSONFileSync<T extends JToken>(filePath: string,opt:LoadJsonFileOpt<T>): T
165
177
  export function loadJSONFileSync<T extends JToken>(filePath: string,opt?:LoadJsonFileOpt<T>): T {
166
- if (path.extname(filePath) !== '.json') filePath += '.json';
167
-
168
- let str = "";
178
+ if(opt?.forceExt!==true && path.extname(filePath) !== '.json')
179
+ filePath += '.json';
169
180
 
170
- // 判断文件路径是否存在
171
- if(pathExistsSync(filePath))
172
- str = fs.readFileSync(filePath, "utf-8");
181
+ const str = pathExistsSync(filePath)
182
+ ? fs.readFileSync(filePath, "utf-8")
183
+ : "";
173
184
 
174
185
  // 如果不存在则返回默认值
175
186
  if (str == "" || str == null){
@@ -192,19 +203,19 @@ export async function loadJSONFile(filePath: string): Promise<JToken>
192
203
  * @async
193
204
  * @param filePath - 文件路径
194
205
  * @param opt - 可选参数
195
- * @param opt.default - 默认值
196
- * @param opt.json5 - json5模式
206
+ * @param opt.default - 默认值
207
+ * @param opt.json5 - json5模式
208
+ * @param opt.forceExt - 不自动修改扩展名为json
197
209
  * @returns 加载完成的对象或默认值
198
210
  */
199
211
  export async function loadJSONFile<T extends JToken>(filePath: string,opt:LoadJsonFileOpt<T>): Promise<T>
200
212
  export async function loadJSONFile<T extends JToken>(filePath: string,opt?:LoadJsonFileOpt<T>): Promise<T> {
201
- if (path.extname(filePath) !== '.json') filePath += '.json';
202
-
203
- let str = "";
213
+ if(opt?.forceExt!==true && path.extname(filePath) !== '.json')
214
+ filePath += '.json';
204
215
 
205
- // 判断文件路径是否存在
206
- if(await pathExists(filePath))
207
- str = await fs.promises.readFile(filePath, "utf-8");
216
+ const str = (await pathExists(filePath))
217
+ ? await fs.promises.readFile(filePath, "utf-8")
218
+ : "";
208
219
 
209
220
  // 如果不存在则返回默认值
210
221
  if (str == "" || str == null){
@@ -222,13 +233,18 @@ export async function loadJSONFile<T extends JToken>(filePath: string,opt?:LoadJ
222
233
  * @async
223
234
  * @param filePath - 文件路径
224
235
  * @param token - 所要写入的JToken
236
+ * @param opt - 可选参数
237
+ * @param opt.compress - 使用紧凑风格
238
+ * @param opt.forceExt - 不自动修改扩展名为json
225
239
  */
226
240
  export async function writeJSONFile(
227
241
  filePath: string,
228
- token: JToken
242
+ token: JToken,
243
+ opt?: WriteJsonFileOpt
229
244
  ): Promise<void> {
230
- const str = UtilFunc.stringifyJToken(token);
231
- if (path.extname(filePath) !== '.json') filePath += '.json';
245
+ const str = UtilFunc.stringifyJToken(token,opt);
246
+ if(opt?.forceExt!==true && path.extname(filePath) !== '.json')
247
+ filePath += '.json';
232
248
 
233
249
  // 判断文件路径是否存在 不存在则创建
234
250
  if(!(await pathExists(filePath)))
@@ -1,5 +1,5 @@
1
1
  import * as crypto from "crypto";
2
- import { AnyFunc, ComposedClass, ComposedMixinable, ComposedRefMixinable, ExtractOutcome, IJData, JObject, JToken, Keyable, Literal, Matchable, MatchableFlag, Mixinable, Outcome, ReqStat, ReqVerifyFn, ProperSubsetCheck, RefMixinable, UnionToIntersection, Await } from "@src/UtilInterfaces";
2
+ import { AnyFunc, ComposedClass, ComposedMixinable, ComposedRefMixinable, ExtractOutcome, IJData, JObject, JToken, Keyable, Literal, Matchable, MatchableFlag, Mixinable, Outcome, ReqStat, ReqVerifyFn, ProperSubsetCheck, RefMixinable, UnionToIntersection, Await, AnyRecord } 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";
@@ -18,6 +18,14 @@ type ExecOpt = Partial<{
18
18
  errlvl:LogLevel,
19
19
  }>
20
20
 
21
+ /**序列化选项 */
22
+ type StringifyOpt = Partial<{
23
+ /**使用紧凑风格 */
24
+ compress:boolean;
25
+ /**插入的空格 数字为空格数量 默认为制表符\t */
26
+ space:string|number|null|undefined;
27
+ }>
28
+
21
29
  /**Promise重试选项 */
22
30
  export type RepeatPromiseOpt = Partial<{
23
31
  /**重试次数 默认3*/
@@ -59,7 +67,7 @@ static getTime(): number {
59
67
  * @param defaultVal - 默认值
60
68
  * @returns 最终值
61
69
  */
62
- static initField<T extends object,K extends keyof T>(
70
+ static initField<T extends AnyRecord,K extends keyof T>(
63
71
  obj: T,
64
72
  field: K,
65
73
  defaultVal: T[K]
@@ -333,7 +341,7 @@ static timelimitPromise<T>
333
341
  * @returns 混合完成的类
334
342
  */
335
343
  static composeClassPart
336
- <Base extends object,Mixin extends object,Field extends keyof Mixin>
344
+ <Base extends AnyRecord,Mixin extends AnyRecord,Field extends keyof Mixin>
337
345
  (base:Base,mixin:Mixin,key:string,...fields:Field[]):ComposedClass<Base,Mixin,typeof key,Field>{
338
346
  const compObj = base as any;
339
347
  if(compObj[key]!==undefined)
@@ -374,7 +382,7 @@ static composeClassPart
374
382
  * @deprecated 非必要情况下, 对class定义请使用 composeRefMixinable
375
383
  */
376
384
  static composeMixinable
377
- <Base extends object, Mixins extends Mixinable<any>[]>
385
+ <Base extends AnyRecord, Mixins extends Mixinable<any>[]>
378
386
  (base:Base,...mixins:Mixins):
379
387
  ComposedMixinable<Base,Mixins>{
380
388
  let out = base;
@@ -395,7 +403,7 @@ static composeMixinable
395
403
 
396
404
  /**根据 MIXIN_FIELDS 自动混入 */
397
405
  static composeRefMixinable
398
- <Base extends object, Mixins extends RefMixinable<any,unknown>[]>
406
+ <Base extends AnyRecord, Mixins extends RefMixinable<any,unknown>[]>
399
407
  (base:Base,...mixins:Mixins):
400
408
  ComposedRefMixinable<Base,Mixins>{
401
409
  let out = base;
@@ -421,7 +429,7 @@ static composeRefMixinable
421
429
  * @param mapper - 映射函数,接受一个值和一个键,返回一个新的值
422
430
  * @returns - 一个新的对象,它的属性是原对象的属性经过映射函数处理后的结果
423
431
  */
424
- static mapEntries<T extends object>
432
+ static mapEntries<T extends AnyRecord>
425
433
  (obj: T, mapper: (key: keyof T, value: T[keyof T]) => T[keyof T]): T {
426
434
  return Object.entries(obj).reduce((result, [key, value]) => {
427
435
  result[key as keyof T] = mapper(key as keyof T, value);
@@ -431,13 +439,32 @@ static mapEntries<T extends object>
431
439
 
432
440
  /**将JToken转换为字符串
433
441
  * @param token - 待转换的Token
434
- * @param space - 插入的空格 数字为空格数量 默认为制表符\t
442
+ * @param opt - 可选参数
443
+ * @param opt.space - 插入的空格 数字为空格数量 默认为制表符\t
444
+ * @param opt.compress - 使用紧凑风格
435
445
  * @returns 转换完成的字符串
436
446
  */
437
- static stringifyJToken(token:JToken|IJData,space:string|number|null|undefined="\t"){
438
- if(space==null)
439
- space=undefined;
440
- return JSON.stringify(token,null,space);
447
+ static stringifyJToken(token:JToken|IJData,opt?:StringifyOpt){
448
+ opt ??= {};
449
+ let {compress,space} = opt;
450
+ space ??="\t";
451
+ space = space===null ? undefined : space;
452
+
453
+ if(!compress) return JSON.stringify(token,null,space);
454
+
455
+ const compressReplacer = (key: string, value: any)=> {
456
+ if (Array.isArray(value) && value.every(item =>
457
+ typeof item === 'number' || typeof item === 'string' ||
458
+ typeof item === 'boolean' || item == null))
459
+ return `@@@${JSON.stringify(value)}@@@`;
460
+ const str = JSON.stringify(value);
461
+ if(str.length<=100) return `@@@${str}@@@`;
462
+ return value;
463
+ }
464
+
465
+ return JSON.stringify(token,compressReplacer,space)
466
+ .replace(/"@@@(.*?)@@@"/g,`$1`)
467
+ .replace(/\\([\\"])/g, '$1');
441
468
  }
442
469
 
443
470
  /**代办表 用于队列处理等待 */
@@ -643,7 +670,7 @@ static isSafeNumber(num: unknown): boolean {
643
670
  }
644
671
 
645
672
  /**将一个字段加入一个对象中,将改变对象,返回新类型 */
646
- static bindTo<K extends Keyable, V, B extends {} = {}>
673
+ static bindTo<K extends Keyable, V, B extends AnyRecord = {}>
647
674
  (key: Literal<K>,value: V, base?:B):keyof B extends K
648
675
  ? "Base中已有对应键"&Error
649
676
  : {[P in K | keyof B]: P extends K ? V : P extends keyof B ? B[P] : never;}{
@@ -73,7 +73,7 @@ export type LiteralCheck<L> =
73
73
  L extends null | undefined ? true : false;
74
74
 
75
75
  /**返回将Mixin分配给Base的结果,相同字段时Mixin覆盖Base */
76
- export type AssignObject<Base extends {}, Mixin extends {}> = {
76
+ export type AssignObject<Base extends AnyRecord, Mixin extends AnyRecord> = {
77
77
  [P in keyof Mixin | keyof Base]: P extends keyof Mixin ? Mixin[P] : P extends keyof Base ? Base[P] : never;
78
78
  }
79
79
 
@@ -180,8 +180,17 @@ export type ReflectionAble<Ctor,Constraint={}> = {
180
180
  };
181
181
  /**可反射的 且 构造函数是可混入的类
182
182
  * @template Ctor - 构造器类型
183
- * @template Instance - 实例类型
183
+ * @template Instance - 实例类型 如果采用了内部混入, 那么填入对外实际暴露的类型, 以支持混入多层字段
184
184
  * @template Constraint - 构造器约束
185
+ * @example
186
+ * export class MixinModule implements RefMixinable<typeof MixinModule,MixinModule>{
187
+ * static readonly MIXIN_FIELDS = [
188
+ * 'func_a',
189
+ * 'field_b'
190
+ * ] as const;
191
+ * static readonly MIXIN_KEY = '__mixinModule';
192
+ * CTOR = MixinModule;
193
+ * }
185
194
  */
186
195
  export type RefMixinable<Ctor,Instance,Constraint={}> =
187
196
  ReflectionAble<Ctor,Mixinable<Instance>&Constraint>;
@@ -284,4 +293,14 @@ export type NeedInit = {
284
293
  };
285
294
 
286
295
  /**可选的record */
287
- export type PRecord<K extends Keyable,V> = Partial<Record<K,V>>;
296
+ export type PRecord<K extends Keyable,V> = Partial<Record<K,V>>;
297
+ /**任何Record */
298
+ export type AnyRecord = Record<Keyable,any>;
299
+
300
+ /**注释元组
301
+ * @template T - 提供注释的类型, 索引需从0开始
302
+ */
303
+ export type AnnotableTuple<T extends {[K:number]:unknown},Tuple extends unknown[]=[]> =
304
+ unknown extends T[Tuple['length']]
305
+ ? T & Tuple
306
+ : AnnotableTuple<T,[...Tuple,T[Tuple['length']]]>;