ph-utils 0.17.2 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/lib/dom.d.ts +125 -25
- package/lib/dom.js +40 -6
- package/lib/src/array.d.ts +79 -0
- package/lib/src/array.js +212 -0
- package/lib/src/color.d.ts +55 -0
- package/lib/src/color.js +294 -0
- package/lib/src/config.d.ts +33 -0
- package/lib/src/config.js +99 -0
- package/lib/src/copy.d.ts +11 -0
- package/lib/src/copy.js +101 -0
- package/lib/src/crypto.d.ts +74 -0
- package/lib/src/crypto.js +261 -0
- package/lib/src/crypto_node.d.ts +61 -0
- package/lib/src/crypto_node.js +133 -0
- package/lib/src/date.d.ts +66 -0
- package/lib/src/date.js +202 -0
- package/lib/src/dom.d.ts +265 -0
- package/lib/src/dom.js +635 -0
- package/lib/src/file.d.ts +29 -0
- package/lib/src/file.js +54 -0
- package/lib/src/id.d.ts +68 -0
- package/lib/src/id.js +170 -0
- package/lib/src/index.d.ts +154 -0
- package/lib/src/index.js +239 -0
- package/lib/src/logger.d.ts +62 -0
- package/lib/src/logger.js +122 -0
- package/lib/src/server.d.ts +33 -0
- package/lib/src/server.js +65 -0
- package/lib/src/storage.d.ts +51 -0
- package/lib/src/storage.js +73 -0
- package/lib/src/theme.d.ts +44 -0
- package/lib/src/theme.js +156 -0
- package/lib/src/validator.d.ts +71 -0
- package/lib/src/validator.js +238 -0
- package/lib/src/web.d.ts +30 -0
- package/lib/src/web.js +100 -0
- package/package.json +2 -2
package/lib/src/file.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** nodejs 文件操作工具类 */
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
/**
|
|
5
|
+
* 读取文件内容
|
|
6
|
+
* @example <caption>1. 读取JSON文件, 内容为字符串列表</caption>
|
|
7
|
+
* read<string[]>('a.json', []);
|
|
8
|
+
* @example <caption>2. 读取JSON文件, 内容为对象</caption>
|
|
9
|
+
* read<{ name: string }>('b.json', {});
|
|
10
|
+
* @param filepath 文件路径
|
|
11
|
+
* @param defaultValue 文件不存在时默认值, 不传则抛异常, 如果传递的是对象形式则会将结果转换为 JSON
|
|
12
|
+
* @returns 文件内容
|
|
13
|
+
*/
|
|
14
|
+
export async function read(filepath, defaultValue) {
|
|
15
|
+
let content;
|
|
16
|
+
try {
|
|
17
|
+
content = await fs.readFile(filepath, "utf8");
|
|
18
|
+
if (defaultValue != null && typeof defaultValue === "object") {
|
|
19
|
+
return JSON.parse(content);
|
|
20
|
+
}
|
|
21
|
+
return content;
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (defaultValue === undefined) {
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
return defaultValue;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 写入 JSON 格式的数据到文件
|
|
32
|
+
* @param file 待写入的文件
|
|
33
|
+
* @param data 待写入的数据
|
|
34
|
+
* @param opts 写入配置
|
|
35
|
+
* @property opts.json 是否写入 JSON 格式的数据,写入数据时对数据进行 JSON 格式化,默认为:true
|
|
36
|
+
* @property opts.format 是否在写入 json 数据时,将 JSON 数据格式化2个空格写入, 默认为 true
|
|
37
|
+
*/
|
|
38
|
+
export async function write(file, data, opts) {
|
|
39
|
+
let writeData = data.toString();
|
|
40
|
+
opts = { json: true, format: true, ...opts };
|
|
41
|
+
if (opts.json === true && typeof data === "object") {
|
|
42
|
+
writeData = JSON.stringify(data, null, opts.format === true ? 2 : 0);
|
|
43
|
+
}
|
|
44
|
+
await fs.writeFile(path.resolve(file), writeData);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 根据文件的 stat 获取文件的 etag
|
|
48
|
+
* @param filePath 文件地址
|
|
49
|
+
* @returns file stat etag
|
|
50
|
+
*/
|
|
51
|
+
export async function statTag(filePath) {
|
|
52
|
+
let stat = await fs.stat(filePath);
|
|
53
|
+
return `${stat.size.toString(16)}-${stat.mtimeMs.toString(16)}`;
|
|
54
|
+
}
|
package/lib/src/id.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
type SnowflakeIDInfo = {
|
|
2
|
+
value: string;
|
|
3
|
+
timeOffset: bigint;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
machineId: bigint;
|
|
6
|
+
sequence: bigint;
|
|
7
|
+
epoch: number;
|
|
8
|
+
version: string | undefined;
|
|
9
|
+
};
|
|
10
|
+
/** 雪花ID, 推荐在全局构造一个对象用于生成id */
|
|
11
|
+
export declare class SnowflakeID {
|
|
12
|
+
/** 机器码, 默认为: 1 */
|
|
13
|
+
machineId: bigint;
|
|
14
|
+
/** 起始时间戳, 默认为:1288834974657 */
|
|
15
|
+
epoch: bigint;
|
|
16
|
+
_lastTimestamp: bigint;
|
|
17
|
+
/** 版本号, 默认为: 0 */
|
|
18
|
+
version: number;
|
|
19
|
+
private _sequence;
|
|
20
|
+
/**
|
|
21
|
+
* 构造函数
|
|
22
|
+
*
|
|
23
|
+
* @param machineId 机器标识,默认为1
|
|
24
|
+
* @param epoch 时间戳起始值,默认为1288834974657
|
|
25
|
+
*/
|
|
26
|
+
constructor(machineId?: number, epoch?: number);
|
|
27
|
+
private _getTimestamp;
|
|
28
|
+
private _waitNextMillis;
|
|
29
|
+
/**
|
|
30
|
+
* 生成雪花ID
|
|
31
|
+
*
|
|
32
|
+
* @returns 返回生成的唯一ID字符串
|
|
33
|
+
* @throws 如果时钟回退,抛出错误
|
|
34
|
+
*/
|
|
35
|
+
generate(): string;
|
|
36
|
+
parse(snowflakeID: string, epoch?: number, includeVersion?: boolean): SnowflakeIDInfo;
|
|
37
|
+
}
|
|
38
|
+
/** 将uuid转换为更简单的唯一标记id */
|
|
39
|
+
export declare class ShortUUID {
|
|
40
|
+
private alphabet;
|
|
41
|
+
/**
|
|
42
|
+
* 构造函数,用于初始化字母表
|
|
43
|
+
* @param {string} [alphabet] - 可选参数,用于指定自定义字母表
|
|
44
|
+
* 如果提供了alphabet参数,则将其设置为实例的字母表属性
|
|
45
|
+
* 如果未提供alphabet参数,则使用默认值
|
|
46
|
+
*/
|
|
47
|
+
constructor(alphabet?: string);
|
|
48
|
+
/**
|
|
49
|
+
* 将UUID字符串进行编码处理
|
|
50
|
+
* @param uuid - 需要编码的UUID字符串
|
|
51
|
+
* @returns 编码后的字符串
|
|
52
|
+
*/
|
|
53
|
+
encode(uuid: string, alphabet?: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* 解码短UUID字符串,将其转换为UUID整数和十六进制格式
|
|
56
|
+
* @param shortUUID - 需要解码的短UUID字符串
|
|
57
|
+
* @returns 返回包含UUID整数和十六进制格式的对象
|
|
58
|
+
*/
|
|
59
|
+
decode(shortUUID: string, alphabet?: string): {
|
|
60
|
+
uuidInt: bigint;
|
|
61
|
+
uuid: string;
|
|
62
|
+
};
|
|
63
|
+
private _stringToInt;
|
|
64
|
+
private _intToString;
|
|
65
|
+
private _uuidHexToInt;
|
|
66
|
+
private _uuidIntToHex;
|
|
67
|
+
}
|
|
68
|
+
export {};
|
package/lib/src/id.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/** 雪花ID, 推荐在全局构造一个对象用于生成id */
|
|
2
|
+
export class SnowflakeID {
|
|
3
|
+
/**
|
|
4
|
+
* 构造函数
|
|
5
|
+
*
|
|
6
|
+
* @param machineId 机器标识,默认为1
|
|
7
|
+
* @param epoch 时间戳起始值,默认为1288834974657
|
|
8
|
+
*/
|
|
9
|
+
constructor(machineId = 1, epoch = 1288834974657) {
|
|
10
|
+
/** 版本号, 默认为: 0 */
|
|
11
|
+
this.version = 0;
|
|
12
|
+
this.machineId = BigInt(machineId);
|
|
13
|
+
this.epoch = BigInt(epoch);
|
|
14
|
+
this._lastTimestamp = BigInt(0);
|
|
15
|
+
this._sequence = BigInt(0);
|
|
16
|
+
}
|
|
17
|
+
_getTimestamp() {
|
|
18
|
+
return BigInt(Date.now());
|
|
19
|
+
}
|
|
20
|
+
_waitNextMillis(cTimestamp) {
|
|
21
|
+
let timestamp = cTimestamp;
|
|
22
|
+
while (timestamp <= this._lastTimestamp) {
|
|
23
|
+
timestamp = BigInt(Date.now());
|
|
24
|
+
}
|
|
25
|
+
return timestamp;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 生成雪花ID
|
|
29
|
+
*
|
|
30
|
+
* @returns 返回生成的唯一ID字符串
|
|
31
|
+
* @throws 如果时钟回退,抛出错误
|
|
32
|
+
*/
|
|
33
|
+
generate() {
|
|
34
|
+
let cTimestamp = this._getTimestamp();
|
|
35
|
+
if (cTimestamp < this._lastTimestamp) {
|
|
36
|
+
throw new Error("Clock moved backwards");
|
|
37
|
+
}
|
|
38
|
+
if (cTimestamp === this._lastTimestamp) {
|
|
39
|
+
// TODO: increment sequence
|
|
40
|
+
// 雪花id,末尾: 12位序列号(二进制12个1等于16进制4095),最多4096个(从0到4095)
|
|
41
|
+
this._sequence = (this._sequence + 1n) & BigInt("0xFFF");
|
|
42
|
+
if (this._sequence === 0n) {
|
|
43
|
+
// 同一时间戳,序列号溢出,等待下一毫秒
|
|
44
|
+
cTimestamp = this._waitNextMillis(cTimestamp);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this._sequence = BigInt(0);
|
|
49
|
+
}
|
|
50
|
+
this._lastTimestamp = cTimestamp;
|
|
51
|
+
const timeDiff = cTimestamp - this.epoch;
|
|
52
|
+
let id = (timeDiff << BigInt(22)) |
|
|
53
|
+
(this.machineId << BigInt(12)) |
|
|
54
|
+
this._sequence;
|
|
55
|
+
let idstr = id.toString().padStart(19, "0");
|
|
56
|
+
return `${this.version}${idstr}`;
|
|
57
|
+
}
|
|
58
|
+
parse(snowflakeID, epoch, includeVersion = true) {
|
|
59
|
+
let version = undefined;
|
|
60
|
+
if (includeVersion) {
|
|
61
|
+
snowflakeID = snowflakeID.substring(1);
|
|
62
|
+
version = snowflakeID.substring(0, 1);
|
|
63
|
+
}
|
|
64
|
+
let epochTime = epoch || Number(this.epoch);
|
|
65
|
+
const id = BigInt(snowflakeID);
|
|
66
|
+
// 1FFFFFFFFFF 就是二进制的41个1, 雪花id前面41为为时间戳,间隔部分
|
|
67
|
+
let timeDiff = (id >> BigInt(22)) & BigInt("0x1FFFFFFFFFF");
|
|
68
|
+
const flowTime = Number(timeDiff) + epochTime;
|
|
69
|
+
// 雪花id中间10位为机器标识, 0x3FF(二进制10个1) 进行位运算
|
|
70
|
+
const machineId = (id >> BigInt(12)) & BigInt("0x3FF");
|
|
71
|
+
const sequence = id & BigInt("0xFFF");
|
|
72
|
+
return {
|
|
73
|
+
value: snowflakeID,
|
|
74
|
+
timeOffset: timeDiff,
|
|
75
|
+
timestamp: flowTime,
|
|
76
|
+
machineId: machineId,
|
|
77
|
+
sequence: sequence,
|
|
78
|
+
epoch: epochTime,
|
|
79
|
+
version: version,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** 将uuid转换为更简单的唯一标记id */
|
|
84
|
+
export class ShortUUID {
|
|
85
|
+
/**
|
|
86
|
+
* 构造函数,用于初始化字母表
|
|
87
|
+
* @param {string} [alphabet] - 可选参数,用于指定自定义字母表
|
|
88
|
+
* 如果提供了alphabet参数,则将其设置为实例的字母表属性
|
|
89
|
+
* 如果未提供alphabet参数,则使用默认值
|
|
90
|
+
*/
|
|
91
|
+
constructor(alphabet) {
|
|
92
|
+
this.alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
93
|
+
if (alphabet) {
|
|
94
|
+
this.alphabet = alphabet;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 将UUID字符串进行编码处理
|
|
99
|
+
* @param uuid - 需要编码的UUID字符串
|
|
100
|
+
* @returns 编码后的字符串
|
|
101
|
+
*/
|
|
102
|
+
encode(uuid, alphabet) {
|
|
103
|
+
// 将UUID字符串转换为整数
|
|
104
|
+
const uuidInt = this._uuidHexToInt(uuid);
|
|
105
|
+
// 将整数转换为特定格式的字符串
|
|
106
|
+
return this._intToString(uuidInt, alphabet);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 解码短UUID字符串,将其转换为UUID整数和十六进制格式
|
|
110
|
+
* @param shortUUID - 需要解码的短UUID字符串
|
|
111
|
+
* @returns 返回包含UUID整数和十六进制格式的对象
|
|
112
|
+
*/
|
|
113
|
+
decode(shortUUID, alphabet) {
|
|
114
|
+
const uuidInt = this._stringToInt(shortUUID, alphabet);
|
|
115
|
+
return {
|
|
116
|
+
uuidInt: uuidInt,
|
|
117
|
+
uuid: this._uuidIntToHex(uuidInt),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
_stringToInt(str, alphabet) {
|
|
121
|
+
if (!alphabet)
|
|
122
|
+
alphabet = this.alphabet;
|
|
123
|
+
const alphabetlen = BigInt(alphabet.length);
|
|
124
|
+
let result = BigInt(0);
|
|
125
|
+
let multiplier = BigInt(1);
|
|
126
|
+
const strlen = str.length;
|
|
127
|
+
for (let i = strlen - 1; i >= 0; i--) {
|
|
128
|
+
const char = str[i];
|
|
129
|
+
const index = alphabet.indexOf(char);
|
|
130
|
+
if (index === -1) {
|
|
131
|
+
throw new Error(`Character "${char}" not found in alphabet`);
|
|
132
|
+
}
|
|
133
|
+
result += BigInt(index) * multiplier;
|
|
134
|
+
multiplier *= alphabetlen;
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
_intToString(uuidInt, alphabet) {
|
|
139
|
+
if (!alphabet)
|
|
140
|
+
alphabet = this.alphabet;
|
|
141
|
+
const alphabetlen = BigInt(alphabet.length);
|
|
142
|
+
let num = uuidInt;
|
|
143
|
+
const result = [];
|
|
144
|
+
// uuidInt = d₀ × 1(base的0次方) + d₁ × base + d₂ × base²...
|
|
145
|
+
while (num) {
|
|
146
|
+
const index = Number(num % alphabetlen);
|
|
147
|
+
num = num / alphabetlen;
|
|
148
|
+
result.push(alphabet.charAt(index));
|
|
149
|
+
}
|
|
150
|
+
// 倒序,保证高位在前
|
|
151
|
+
return result.reverse().join("");
|
|
152
|
+
}
|
|
153
|
+
_uuidHexToInt(uuid) {
|
|
154
|
+
const uuidHex = uuid.replaceAll("-", "");
|
|
155
|
+
return BigInt(`0x${uuidHex}`);
|
|
156
|
+
}
|
|
157
|
+
_uuidIntToHex(uuidInt) {
|
|
158
|
+
const uuidHexStr = uuidInt.toString(16);
|
|
159
|
+
if (!/^[0-9a-fA-F]{32}$/.test(uuidHexStr)) {
|
|
160
|
+
throw new Error("Invalid UUID string (must be 32 hex characters)");
|
|
161
|
+
}
|
|
162
|
+
return [
|
|
163
|
+
uuidHexStr.slice(0, 8),
|
|
164
|
+
uuidHexStr.slice(8, 12),
|
|
165
|
+
uuidHexStr.slice(12, 16),
|
|
166
|
+
uuidHexStr.slice(16, 20),
|
|
167
|
+
uuidHexStr.slice(20),
|
|
168
|
+
].join("-");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 验证参数是否为空
|
|
3
|
+
* @param str 待验证的参数
|
|
4
|
+
* @param ignoreWhitespace 如果是字符串是否忽略空格(包括空白字符串以及[\r\t\n]之类的制表符),默认为true
|
|
5
|
+
*/
|
|
6
|
+
export declare function isBlank(str?: any, ignoreWhitespace?: boolean): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* 屏蔽手机号,中间部分用 * 展示
|
|
9
|
+
* @param mobile 待屏蔽的手机号
|
|
10
|
+
* @returns 屏蔽后的手机号,例如:123 **** 1234
|
|
11
|
+
*/
|
|
12
|
+
export declare function shieldMobile(mobile: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* 验证参数是否是数字
|
|
15
|
+
* @param str 待验证的字符串
|
|
16
|
+
* @param numericParam 通过参数标记是否包含小数、正数
|
|
17
|
+
* @param numericParam.isPositive 是否是正数, 默认: false
|
|
18
|
+
* @param numericParam.isFloat 是否是小数, 默认: true
|
|
19
|
+
* @returns true 是数字, false 不是数字
|
|
20
|
+
*/
|
|
21
|
+
export declare function isNumeric(str: string, numericParam?: {
|
|
22
|
+
isPositive?: boolean;
|
|
23
|
+
isFloat?: boolean;
|
|
24
|
+
}): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* 验证参数是否是Boolean 类型
|
|
27
|
+
* @param str 待验证的字符串
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
export declare function isBoolean(str: string): boolean;
|
|
31
|
+
/** 生成随机数的选项 */
|
|
32
|
+
interface RandomStringOption {
|
|
33
|
+
/** 生成指定长度的随机字符串 */
|
|
34
|
+
length: number;
|
|
35
|
+
/** 是否包含英文字母, 默认为: true */
|
|
36
|
+
hasLetter?: boolean;
|
|
37
|
+
/** 生成纯数字的随机数时, 首位是否允许为 0, 默认为: true */
|
|
38
|
+
firstIsZero?: boolean;
|
|
39
|
+
}
|
|
40
|
+
interface RangeRandomOption {
|
|
41
|
+
/** 配合 max 生成 [min~max] 之间的随机数 */
|
|
42
|
+
min: number;
|
|
43
|
+
/** 配合 min 生成 [min~max] 之间的随机数 */
|
|
44
|
+
max: number;
|
|
45
|
+
/** 生成的随机数,是否包含 max, 默认: false */
|
|
46
|
+
hasEnd?: boolean;
|
|
47
|
+
/** 生成的随机数是否是整数, 默认: true */
|
|
48
|
+
isInteger?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 生成指定长度的随机数
|
|
52
|
+
*
|
|
53
|
+
* @param len - 生成的随机数长度
|
|
54
|
+
*
|
|
55
|
+
* @example <caption>1. 生成指定长度的随机字符串</caption>
|
|
56
|
+
* random(1); // 长度为 1 的随机字符串
|
|
57
|
+
*/
|
|
58
|
+
export declare function random(len: number): string;
|
|
59
|
+
/**
|
|
60
|
+
* 生成介于 [min, max] 之间的随机数
|
|
61
|
+
*
|
|
62
|
+
* @param option 配置项
|
|
63
|
+
* @param option.min 生成介于 [min, max] 之间的随机数
|
|
64
|
+
* @param option.max 生成介于 [min, max] 之间的随机数
|
|
65
|
+
* @param option.hasEnd 生成的随机数,是否包含 max, 默认: false
|
|
66
|
+
* @param option.isInteger 生成的随机数是否是整数, 默认: true
|
|
67
|
+
*/
|
|
68
|
+
export declare function random(option: RangeRandomOption): number;
|
|
69
|
+
/**
|
|
70
|
+
* 生成指定长度随机数
|
|
71
|
+
*
|
|
72
|
+
* @param option 配置项
|
|
73
|
+
* @param option.length 生成的随机数长度
|
|
74
|
+
* @param option.hasLetter 是否包含英文字母, 默认为: true
|
|
75
|
+
* @param option.firstIsZero 生成纯数字的随机数时, 首位是否允许为 0, 默认为: true
|
|
76
|
+
*
|
|
77
|
+
* @example <caption>2. 生成纯数字且首位不能为0长度为1的随机字符</caption>
|
|
78
|
+
* random({ length: 1, hasLetter: false, firstIsZero: false })
|
|
79
|
+
*/
|
|
80
|
+
export declare function random(option: RandomStringOption): string;
|
|
81
|
+
/**
|
|
82
|
+
* 带有错误名称标记的错误类型
|
|
83
|
+
*/
|
|
84
|
+
export declare class BaseError extends Error {
|
|
85
|
+
/**
|
|
86
|
+
* 错误名称,类似于 Java 中的不同的 Exception[NullPointerException];
|
|
87
|
+
* 增加 name 字段,表明不同的错误,当需要根据不同的错误执行不同的处理的时候,会很有用
|
|
88
|
+
*/
|
|
89
|
+
name: string;
|
|
90
|
+
/**
|
|
91
|
+
* 构造一个 name = BaseError 的错误信息
|
|
92
|
+
* @param message 错误描述
|
|
93
|
+
*/
|
|
94
|
+
constructor(message: string);
|
|
95
|
+
/**
|
|
96
|
+
*
|
|
97
|
+
* @param name 错误名称
|
|
98
|
+
* @param message 错误描述
|
|
99
|
+
*/
|
|
100
|
+
constructor(name: string, message: string);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 将金额数字格式化为金额格式显示并且会保留两位小数[去除多余的位数,不是四舍五入,而是直接舍去] 1234523432.23 => 123,123,123.23
|
|
104
|
+
* @param {number} number 待转换的金额数字
|
|
105
|
+
* @return string
|
|
106
|
+
*/
|
|
107
|
+
export declare function formatMoney(number: number): string;
|
|
108
|
+
/**
|
|
109
|
+
* 将风格由大写风格转换为下划线风格: HelloWorld -> hello-world
|
|
110
|
+
* @param name 命名, 例如: HelloWorld
|
|
111
|
+
* @param connector 连接符, 默认为: _
|
|
112
|
+
*/
|
|
113
|
+
export declare function snakeCaseStyle(name: string, connector?: string): string;
|
|
114
|
+
/**
|
|
115
|
+
* 对数字进行四舍五入处理
|
|
116
|
+
* @param num 需要进行四舍五入的数字
|
|
117
|
+
* @param precision 精度,默认为2,即保留小数点后两位
|
|
118
|
+
* @param roundType 舍入类型,默认为0,提供三种取值:
|
|
119
|
+
* 0: 标准四舍五入
|
|
120
|
+
* 1: 向上取整
|
|
121
|
+
* 2: 向下取整
|
|
122
|
+
* @returns 返回经过指定方式舍入后的数字
|
|
123
|
+
*/
|
|
124
|
+
export declare function round(num: number, precision?: number, roundType?: 0 | 1 | 2): number;
|
|
125
|
+
/**
|
|
126
|
+
* 反转字符串
|
|
127
|
+
*/
|
|
128
|
+
export declare function reverseStr(str: string): string;
|
|
129
|
+
/** 数据格式化配置 */
|
|
130
|
+
interface FormDataConfig<T> {
|
|
131
|
+
/** 配置需要转换为数字的字段 */
|
|
132
|
+
numberFields?: (keyof T)[];
|
|
133
|
+
/** 配置需要转换为字符串的字段 */
|
|
134
|
+
stringFields?: (keyof T)[];
|
|
135
|
+
/** 自定义的格式化 */
|
|
136
|
+
formatter?: {
|
|
137
|
+
[K in keyof T]?: "number" | "string" | ((value: any) => number | string);
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 嵌套的 json 指定 key 数据
|
|
142
|
+
* @param data JSON格式数据
|
|
143
|
+
* @param keys 待获取的数据 key, 可以通过 [.] 获取嵌套数据, 例如: a.b.c
|
|
144
|
+
* @returns
|
|
145
|
+
*/
|
|
146
|
+
export declare function getJSONValue(data: Record<string, any>, keystr: string): Record<string, any> | null;
|
|
147
|
+
/**
|
|
148
|
+
* 数据格式化主要用于数据类型转换
|
|
149
|
+
* @param data 待转换数据类型的数据
|
|
150
|
+
* @param config 转换配置
|
|
151
|
+
* @returns
|
|
152
|
+
*/
|
|
153
|
+
export declare function formatData<T extends Record<string, any>>(data: T, config?: FormDataConfig<T>): T;
|
|
154
|
+
export {};
|
package/lib/src/index.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* node 和 web 通用的工具类
|
|
3
|
+
*/
|
|
4
|
+
/** 包含字母+数字的随机数字符 */
|
|
5
|
+
const RANDOM_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
6
|
+
/** 只包含字母的随机数字符 */
|
|
7
|
+
const NUMBER_RANDOM_CHARTS = "0123456789";
|
|
8
|
+
/**
|
|
9
|
+
* 验证参数是否为空
|
|
10
|
+
* @param str 待验证的参数
|
|
11
|
+
* @param ignoreWhitespace 如果是字符串是否忽略空格(包括空白字符串以及[\r\t\n]之类的制表符),默认为true
|
|
12
|
+
*/
|
|
13
|
+
export function isBlank(str, ignoreWhitespace = true) {
|
|
14
|
+
if (str == null) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return ((ignoreWhitespace && typeof str === "string"
|
|
18
|
+
? str.trim().length
|
|
19
|
+
: str.length) === 0);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 屏蔽手机号,中间部分用 * 展示
|
|
23
|
+
* @param mobile 待屏蔽的手机号
|
|
24
|
+
* @returns 屏蔽后的手机号,例如:123 **** 1234
|
|
25
|
+
*/
|
|
26
|
+
export function shieldMobile(mobile) {
|
|
27
|
+
const x1 = Math.floor(mobile.length / 2);
|
|
28
|
+
const x2 = Math.ceil(x1 / 2);
|
|
29
|
+
const shields = [" "];
|
|
30
|
+
for (let i = 0; i < x1 - 1; i++) {
|
|
31
|
+
shields.push("*");
|
|
32
|
+
}
|
|
33
|
+
shields.push(" ");
|
|
34
|
+
return (mobile.substring(0, x2) + shields.join("") + mobile.substring(x2 + x1 - 1));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 验证参数是否是数字
|
|
38
|
+
* @param str 待验证的字符串
|
|
39
|
+
* @param numericParam 通过参数标记是否包含小数、正数
|
|
40
|
+
* @param numericParam.isPositive 是否是正数, 默认: false
|
|
41
|
+
* @param numericParam.isFloat 是否是小数, 默认: true
|
|
42
|
+
* @returns true 是数字, false 不是数字
|
|
43
|
+
*/
|
|
44
|
+
export function isNumeric(str, numericParam) {
|
|
45
|
+
numericParam = { isPositive: false, isFloat: true, ...numericParam };
|
|
46
|
+
const symbol = numericParam.isPositive ? "[+]?" : "[+-]?";
|
|
47
|
+
const main = numericParam.isFloat ? "([0-9]*[.])?[0-9]+" : "[0-9]+";
|
|
48
|
+
return new RegExp("^" + symbol + main + "$").test(str);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 验证参数是否是Boolean 类型
|
|
52
|
+
* @param str 待验证的字符串
|
|
53
|
+
* @returns
|
|
54
|
+
*/
|
|
55
|
+
export function isBoolean(str) {
|
|
56
|
+
return ["true", "false"].indexOf(str) >= 0;
|
|
57
|
+
}
|
|
58
|
+
export function random(opts) {
|
|
59
|
+
if (typeof opts === "object" && opts.min != null && opts.max != null) {
|
|
60
|
+
const randomNum = Math.random();
|
|
61
|
+
/* 生成两个数字之间的随机数(number) */
|
|
62
|
+
const end = opts.hasEnd ? 1 : 0;
|
|
63
|
+
const resRandom = randomNum * (opts.max - opts.min + end) + opts.min;
|
|
64
|
+
return opts.isInteger !== false ? Math.floor(resRandom) : resRandom;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
if (typeof opts === "object" && opts.length == null) {
|
|
68
|
+
throw new Error("random_length_cannot_null");
|
|
69
|
+
}
|
|
70
|
+
let len = typeof opts === "object" ? opts.length : opts;
|
|
71
|
+
/* 生成指定长度的随机数 */
|
|
72
|
+
let chars = RANDOM_CHARS;
|
|
73
|
+
if (typeof opts === "object" && opts.hasLetter === false) {
|
|
74
|
+
chars = NUMBER_RANDOM_CHARTS;
|
|
75
|
+
}
|
|
76
|
+
const resRandom = Array.from({ length: len }, () => chars.charAt(random({ min: 0, max: chars.length - 1, hasEnd: true }))).join("");
|
|
77
|
+
if (typeof opts === "object" &&
|
|
78
|
+
opts.firstIsZero === false &&
|
|
79
|
+
resRandom.indexOf("0") === 0) {
|
|
80
|
+
return random(opts);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
return resRandom;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 带有错误名称标记的错误类型
|
|
89
|
+
*/
|
|
90
|
+
export class BaseError extends Error {
|
|
91
|
+
constructor() {
|
|
92
|
+
if (arguments.length === 1) {
|
|
93
|
+
super(arguments[0]);
|
|
94
|
+
this.name = "BaseError";
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
super(arguments[1]);
|
|
98
|
+
this.name = arguments[0];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 将金额数字格式化为金额格式显示并且会保留两位小数[去除多余的位数,不是四舍五入,而是直接舍去] 1234523432.23 => 123,123,123.23
|
|
104
|
+
* @param {number} number 待转换的金额数字
|
|
105
|
+
* @return string
|
|
106
|
+
*/
|
|
107
|
+
export function formatMoney(number) {
|
|
108
|
+
if (typeof Intl.NumberFormat !== "undefined") {
|
|
109
|
+
const formatter = new Intl.NumberFormat("zh-CN", {
|
|
110
|
+
style: "decimal",
|
|
111
|
+
maximumFractionDigits: 2,
|
|
112
|
+
});
|
|
113
|
+
return formatter.format(number);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
number = number || 0;
|
|
117
|
+
const negative = "";
|
|
118
|
+
const base = String(parseInt(number, 10)); // 获取数字整数部分
|
|
119
|
+
const mod = base.length > 3 ? base.length % 3 : 0;
|
|
120
|
+
/*
|
|
121
|
+
* 利用 正则前瞻 (?=) 将3位数字后面还紧跟一位数字的三位数字替换为 数字, 的形式
|
|
122
|
+
*/
|
|
123
|
+
const numberStr = String(number);
|
|
124
|
+
const usePrecision = numberStr.indexOf(".");
|
|
125
|
+
let dotStr = usePrecision > 0 ? numberStr.slice(usePrecision + 1) : "00";
|
|
126
|
+
dotStr = dotStr.length > 2 ? dotStr.slice(0, 2) : dotStr;
|
|
127
|
+
return (negative +
|
|
128
|
+
(mod ? base.slice(0, mod) + "," : "") +
|
|
129
|
+
base.slice(mod).replace(/(\d{3})(?=\d)/g, "$1,") +
|
|
130
|
+
"." +
|
|
131
|
+
dotStr);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 将风格由大写风格转换为下划线风格: HelloWorld -> hello-world
|
|
136
|
+
* @param name 命名, 例如: HelloWorld
|
|
137
|
+
* @param connector 连接符, 默认为: _
|
|
138
|
+
*/
|
|
139
|
+
export function snakeCaseStyle(name, connector = "-") {
|
|
140
|
+
return name.replace(/([A-Z])/g, (match, p1, offset) => (offset > 0 ? connector : "") + match.toLowerCase());
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* 对数字进行四舍五入处理
|
|
144
|
+
* @param num 需要进行四舍五入的数字
|
|
145
|
+
* @param precision 精度,默认为2,即保留小数点后两位
|
|
146
|
+
* @param roundType 舍入类型,默认为0,提供三种取值:
|
|
147
|
+
* 0: 标准四舍五入
|
|
148
|
+
* 1: 向上取整
|
|
149
|
+
* 2: 向下取整
|
|
150
|
+
* @returns 返回经过指定方式舍入后的数字
|
|
151
|
+
*/
|
|
152
|
+
export function round(num, precision = 2, roundType = 0) {
|
|
153
|
+
// 计算精度因子,用于后续四舍五入计算
|
|
154
|
+
const factor = Math.pow(10, precision);
|
|
155
|
+
switch (roundType) {
|
|
156
|
+
case 0:
|
|
157
|
+
// 标准四舍五入
|
|
158
|
+
return Math.round(num * factor) / factor;
|
|
159
|
+
case 1:
|
|
160
|
+
// 向上取整
|
|
161
|
+
return Math.ceil(num * factor) / factor;
|
|
162
|
+
case 2:
|
|
163
|
+
// 向下取整
|
|
164
|
+
return Math.floor(num * factor) / factor;
|
|
165
|
+
default:
|
|
166
|
+
// 如果传入的roundType不是预期的值,则直接返回原始数字
|
|
167
|
+
return num;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* 反转字符串
|
|
172
|
+
*/
|
|
173
|
+
export function reverseStr(str) {
|
|
174
|
+
return str.split("").reverse().join("");
|
|
175
|
+
}
|
|
176
|
+
function getObjKeyValue(data, key) {
|
|
177
|
+
if (data == null)
|
|
178
|
+
return null;
|
|
179
|
+
return data[key];
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* 嵌套的 json 指定 key 数据
|
|
183
|
+
* @param data JSON格式数据
|
|
184
|
+
* @param keys 待获取的数据 key, 可以通过 [.] 获取嵌套数据, 例如: a.b.c
|
|
185
|
+
* @returns
|
|
186
|
+
*/
|
|
187
|
+
export function getJSONValue(data, keystr) {
|
|
188
|
+
if (data == null)
|
|
189
|
+
return null;
|
|
190
|
+
const keys = keystr.split(".");
|
|
191
|
+
let res = data;
|
|
192
|
+
for (const key of keys) {
|
|
193
|
+
res = getObjKeyValue(res, key);
|
|
194
|
+
if (res == null)
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
return res;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* 数据格式化主要用于数据类型转换
|
|
201
|
+
* @param data 待转换数据类型的数据
|
|
202
|
+
* @param config 转换配置
|
|
203
|
+
* @returns
|
|
204
|
+
*/
|
|
205
|
+
export function formatData(data, config) {
|
|
206
|
+
const cfg = {
|
|
207
|
+
numberFields: [],
|
|
208
|
+
stringFields: [],
|
|
209
|
+
formatter: {},
|
|
210
|
+
...config,
|
|
211
|
+
};
|
|
212
|
+
const res = {};
|
|
213
|
+
for (const key in data) {
|
|
214
|
+
let value = getJSONValue(data, key);
|
|
215
|
+
let formater;
|
|
216
|
+
if (key in cfg.formatter) {
|
|
217
|
+
formater = cfg.formatter[key];
|
|
218
|
+
}
|
|
219
|
+
if (cfg.numberFields.includes(key)) {
|
|
220
|
+
formater = "number";
|
|
221
|
+
}
|
|
222
|
+
if (cfg.stringFields.includes(key)) {
|
|
223
|
+
formater = "string";
|
|
224
|
+
}
|
|
225
|
+
if (formater != null) {
|
|
226
|
+
if (typeof formater == "function") {
|
|
227
|
+
value = formater(value);
|
|
228
|
+
}
|
|
229
|
+
else if (formater == "number") {
|
|
230
|
+
value = Number(value);
|
|
231
|
+
}
|
|
232
|
+
else if (formater == "string") {
|
|
233
|
+
value = String(value);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
res[key] = value;
|
|
237
|
+
}
|
|
238
|
+
return res;
|
|
239
|
+
}
|