@anjianshi/utils 1.2.6 → 1.3.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/env-node/env-reader.d.ts +12 -0
- package/env-node/env-reader.js +31 -0
- package/env-node/{logging.d.ts → logging/handlers.d.ts} +1 -6
- package/env-node/{logging.js → logging/handlers.js} +1 -12
- package/env-node/logging/index.d.ts +11 -0
- package/env-node/logging/index.js +14 -0
- package/env-node/typeorm/adapt-logging.d.ts +11 -0
- package/env-node/typeorm/adapt-logging.js +42 -0
- package/env-node/typeorm/index.d.ts +31 -0
- package/env-node/typeorm/index.js +39 -0
- package/lang/index.d.ts +1 -0
- package/lang/index.js +1 -0
- package/lang/may-success.d.ts +40 -0
- package/lang/may-success.js +27 -0
- package/lang/types.d.ts +12 -43
- package/lang/types.js +0 -13
- package/logging/index.js +1 -1
- package/md5.d.ts +30 -0
- package/md5.js +309 -0
- package/package.json +3 -1
- package/src/env-node/env-reader.ts +33 -0
- package/src/env-node/{logging.ts → logging/handlers.ts} +1 -21
- package/src/env-node/logging/index.ts +16 -0
- package/src/env-node/typeorm/adapt-logging.ts +54 -0
- package/src/env-node/typeorm/index.ts +62 -0
- package/src/lang/index.ts +1 -0
- package/src/lang/may-success.ts +57 -0
- package/src/lang/types.ts +14 -59
- package/src/logging/index.ts +1 -1
- package/src/md5.ts +319 -0
- package/src/url.ts +48 -55
- package/src/validators/array.ts +62 -0
- package/src/validators/base.ts +49 -0
- package/src/validators/boolean.ts +24 -0
- package/src/validators/factories.ts +47 -0
- package/src/validators/index.ts +9 -0
- package/src/validators/number.ts +43 -0
- package/src/validators/object.ts +70 -0
- package/src/validators/string.ts +55 -0
- package/url.d.ts +31 -15
- package/url.js +22 -28
- package/validators/array.d.ts +20 -0
- package/validators/array.js +44 -0
- package/validators/base.d.ts +26 -0
- package/validators/base.js +28 -0
- package/validators/boolean.d.ts +4 -0
- package/validators/boolean.js +28 -0
- package/validators/factories.d.ts +18 -0
- package/validators/factories.js +41 -0
- package/validators/index.d.ts +7 -0
- package/validators/index.js +7 -0
- package/validators/number.d.ts +15 -0
- package/validators/number.js +32 -0
- package/validators/object.d.ts +20 -0
- package/validators/object.js +52 -0
- package/validators/string.d.ts +17 -0
- package/validators/string.js +35 -0
package/src/lang/types.ts
CHANGED
|
@@ -16,24 +16,16 @@ export function tuple<T extends unknown[]>(...elements: T) {
|
|
|
16
16
|
return elements
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
* 将一个对象中的指定 key 设为必须的
|
|
21
|
-
*/
|
|
19
|
+
/** 将一个对象中的指定 key 设为必须的 */
|
|
22
20
|
export type RequiredFields<T, K extends keyof T> = Omit<T, K> & Pick<Required<T>, K>
|
|
23
21
|
|
|
24
|
-
/**
|
|
25
|
-
* 将一个对象中的指定 key 设为非必须的
|
|
26
|
-
*/
|
|
22
|
+
/** 将一个对象中的指定 key 设为非必须的 */
|
|
27
23
|
export type OptionalFields<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
|
|
28
24
|
|
|
29
|
-
/**
|
|
30
|
-
* 用 ReplaceT 中的字段定义代替 T 中的
|
|
31
|
-
*/
|
|
25
|
+
/** 用 ReplaceT 中的字段定义代替 T 中的 */
|
|
32
26
|
export type ReplaceFields<T, ReplaceT> = Omit<T, keyof ReplaceT> & ReplaceT
|
|
33
27
|
|
|
34
|
-
/**
|
|
35
|
-
* 获取一个对象所有 value 的集合
|
|
36
|
-
*/
|
|
28
|
+
/** 获取一个对象所有 value 的集合 */
|
|
37
29
|
export type ValueOf<T> = T extends { [_ in keyof T]: infer U } ? U : never
|
|
38
30
|
|
|
39
31
|
/**
|
|
@@ -49,60 +41,25 @@ export type KnownKeys<T> = ValueOf<{
|
|
|
49
41
|
[K in keyof T]: string extends K ? never : number extends K ? never : K
|
|
50
42
|
}>
|
|
51
43
|
|
|
52
|
-
/**
|
|
53
|
-
* 排除对象中指定类型的项目
|
|
54
|
-
*/
|
|
44
|
+
/** 排除对象中指定类型的项目 */
|
|
55
45
|
export type ExcludePropertiesOfType<T, ExcludeValueT> = Pick<
|
|
56
46
|
T,
|
|
57
47
|
{ [K in keyof T]: T[K] extends ExcludeValueT ? never : K }[keyof T]
|
|
58
48
|
>
|
|
59
49
|
|
|
60
50
|
/**
|
|
61
|
-
*
|
|
51
|
+
* 生成不包含指定 key 的类型
|
|
52
|
+
* 与 Omit<T, Keys> 的区别是
|
|
62
53
|
*/
|
|
54
|
+
export type ExcludeKeys<T, ExcludeKeys> = Pick<
|
|
55
|
+
T,
|
|
56
|
+
{ [K in keyof T]: K extends ExcludeKeys ? never : K }[keyof T]
|
|
57
|
+
>
|
|
58
|
+
|
|
59
|
+
/** 排除对象的方法(仅保留属性) */
|
|
63
60
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
64
61
|
export type ExcluceMethods<T> = ExcludePropertiesOfType<T, Function>
|
|
65
62
|
|
|
66
|
-
/**
|
|
67
|
-
* 所有“可能失败”的操作都可使用此类型作为返回值
|
|
68
|
-
*/
|
|
69
|
-
export interface Success<T = void> {
|
|
70
|
-
success: true
|
|
71
|
-
data: T
|
|
72
|
-
}
|
|
73
|
-
export interface Failed<ET = string> {
|
|
74
|
-
success: false
|
|
75
|
-
error: ET
|
|
76
|
-
code?: number | string
|
|
77
|
-
}
|
|
78
|
-
export type MaySuccess<T = void, ET = string> = Success<T> | Failed<ET>
|
|
79
|
-
|
|
80
|
-
function success(): Success
|
|
81
|
-
function success<T>(data: T): Success<T>
|
|
82
|
-
function success<T = void>(data?: T) {
|
|
83
|
-
return { success: true, data }
|
|
84
|
-
}
|
|
85
|
-
export { success }
|
|
86
|
-
|
|
87
|
-
export function failed<ET>(error: ET, code?: number | string): Failed<ET> {
|
|
88
|
-
return { success: false, error, code }
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* 若传入值为 success,格式化其 data;否则原样返回错误
|
|
93
|
-
* 支持传入会返回 MaySuccess 的 Promise
|
|
94
|
-
*/
|
|
95
|
-
function formatSuccess<T, ET, FT>(item: MaySuccess<T, ET>, formatter: (data: T) => FT): MaySuccess<FT, ET> // prettier-ignore
|
|
96
|
-
function formatSuccess<T, ET, FT>(item: Promise<MaySuccess<T, ET>>, formatter: (data: T) => FT): Promise<MaySuccess<FT, ET>> // prettier-ignore
|
|
97
|
-
function formatSuccess<T, ET, FT>(
|
|
98
|
-
item: MaySuccess<T, ET> | Promise<MaySuccess<T, ET>>,
|
|
99
|
-
formatter: (data: T) => FT
|
|
100
|
-
) {
|
|
101
|
-
if ('then' in item) return item.then(finalItem => formatSuccess(finalItem, formatter))
|
|
102
|
-
return item.success ? { ...item, data: formatter(item.data) } : item
|
|
103
|
-
}
|
|
104
|
-
export { formatSuccess }
|
|
105
|
-
|
|
106
63
|
/**
|
|
107
64
|
* 确认变量是否有值
|
|
108
65
|
* 注意:空字符串和数字 0 也会判定为没有值
|
|
@@ -118,9 +75,7 @@ function truthy<T>(value: T | string | number | boolean | null | undefined) {
|
|
|
118
75
|
}
|
|
119
76
|
export { truthy }
|
|
120
77
|
|
|
121
|
-
/**
|
|
122
|
-
* 定义 JSON 数据
|
|
123
|
-
*/
|
|
78
|
+
/** 定义 JSON 数据 */
|
|
124
79
|
export type JSONData = number | boolean | string | null | JSONData[] | { [key: string]: JSONData }
|
|
125
80
|
|
|
126
81
|
/**
|
package/src/logging/index.ts
CHANGED
|
@@ -44,7 +44,7 @@ export class Logger {
|
|
|
44
44
|
|
|
45
45
|
static getRealLevel(raw: LogLevel | string) {
|
|
46
46
|
if (typeof raw === 'string') {
|
|
47
|
-
raw = raw.
|
|
47
|
+
raw = raw.toLowerCase()
|
|
48
48
|
if (logLevelMap[raw] === undefined) throw new Error('Not supported log level: ' + raw)
|
|
49
49
|
return logLevelMap[raw]!
|
|
50
50
|
}
|
package/src/md5.ts
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/* eslint-disable no-multi-assign, @typescript-eslint/restrict-plus-operands */
|
|
2
|
+
/**
|
|
3
|
+
* MD5 算法来自:https://github.com/emn178/js-md5
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export function md5(content: string | ArrayBuffer) {
|
|
7
|
+
const md5 = new MD5()
|
|
8
|
+
md5.update(content)
|
|
9
|
+
return md5.hex()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// -------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 使用方法:
|
|
16
|
+
* const md5 = new MD5()
|
|
17
|
+
* md5.update(xxx) // 对于大文件,可以拆分开,多次调用 md5.update()
|
|
18
|
+
* const hash = md5.hex()
|
|
19
|
+
*/
|
|
20
|
+
export class MD5 {
|
|
21
|
+
private readonly buffer8: Uint8Array
|
|
22
|
+
private readonly blocks: Uint32Array
|
|
23
|
+
|
|
24
|
+
private h0 = 0
|
|
25
|
+
private h1 = 0
|
|
26
|
+
private h2 = 0
|
|
27
|
+
private h3 = 0
|
|
28
|
+
private start = 0
|
|
29
|
+
private bytes = 0
|
|
30
|
+
private hBytes = 0
|
|
31
|
+
private lastByteIndex = 0
|
|
32
|
+
|
|
33
|
+
private finalized = false
|
|
34
|
+
private hashed = false
|
|
35
|
+
private first = true
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
const buffer = new ArrayBuffer(68)
|
|
39
|
+
this.buffer8 = new Uint8Array(buffer)
|
|
40
|
+
this.blocks = new Uint32Array(buffer)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
update(message: string | number[] | Uint8Array | ArrayBuffer) {
|
|
44
|
+
if (this.finalized) return
|
|
45
|
+
|
|
46
|
+
if (message instanceof ArrayBuffer) {
|
|
47
|
+
message = new Uint8Array(message)
|
|
48
|
+
}
|
|
49
|
+
if (typeof message !== 'string' && !Array.isArray(message) && !ArrayBuffer.isView(message)) {
|
|
50
|
+
throw new Error('input is invalid type')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const length = message.length
|
|
54
|
+
const { blocks, buffer8 } = this
|
|
55
|
+
|
|
56
|
+
let code: number
|
|
57
|
+
let index = 0
|
|
58
|
+
let i: number
|
|
59
|
+
|
|
60
|
+
while (index < length) {
|
|
61
|
+
if (this.hashed) {
|
|
62
|
+
this.hashed = false
|
|
63
|
+
blocks[0] = blocks[16]!
|
|
64
|
+
// prettier-ignore
|
|
65
|
+
blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] =
|
|
66
|
+
blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] =
|
|
67
|
+
blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (typeof message !== 'string') {
|
|
71
|
+
for (i = this.start; index < length && i < 64; ++index) {
|
|
72
|
+
buffer8[i++] = message[index]!
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
for (i = this.start; index < length && i < 64; ++index) {
|
|
76
|
+
code = message.charCodeAt(index)
|
|
77
|
+
if (code < 0x80) {
|
|
78
|
+
buffer8[i++] = code
|
|
79
|
+
} else if (code < 0x800) {
|
|
80
|
+
buffer8[i++] = 0xc0 | (code >> 6)
|
|
81
|
+
buffer8[i++] = 0x80 | (code & 0x3f)
|
|
82
|
+
} else if (code < 0xd800 || code >= 0xe000) {
|
|
83
|
+
buffer8[i++] = 0xe0 | (code >> 12)
|
|
84
|
+
buffer8[i++] = 0x80 | ((code >> 6) & 0x3f)
|
|
85
|
+
buffer8[i++] = 0x80 | (code & 0x3f)
|
|
86
|
+
} else {
|
|
87
|
+
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff))
|
|
88
|
+
buffer8[i++] = 0xf0 | (code >> 18)
|
|
89
|
+
buffer8[i++] = 0x80 | ((code >> 12) & 0x3f)
|
|
90
|
+
buffer8[i++] = 0x80 | ((code >> 6) & 0x3f)
|
|
91
|
+
buffer8[i++] = 0x80 | (code & 0x3f)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
this.lastByteIndex = i
|
|
96
|
+
this.bytes += i - this.start
|
|
97
|
+
if (i >= 64) {
|
|
98
|
+
this.start = i - 64
|
|
99
|
+
this.hash()
|
|
100
|
+
this.hashed = true
|
|
101
|
+
} else {
|
|
102
|
+
this.start = i
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (this.bytes > 4294967295) {
|
|
106
|
+
this.hBytes += (this.bytes / 4294967296) << 0
|
|
107
|
+
this.bytes = this.bytes % 4294967296
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private finalize() {
|
|
112
|
+
if (this.finalized) return
|
|
113
|
+
this.finalized = true
|
|
114
|
+
const { blocks } = this
|
|
115
|
+
const i = this.lastByteIndex
|
|
116
|
+
const EXTRA = [128, 32768, 8388608, -2147483648]
|
|
117
|
+
blocks[i >> 2] |= EXTRA[i & 3]!
|
|
118
|
+
if (i >= 56) {
|
|
119
|
+
if (!this.hashed) this.hash()
|
|
120
|
+
blocks[0] = blocks[16]!
|
|
121
|
+
// prettier-ignore
|
|
122
|
+
blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] =
|
|
123
|
+
blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] =
|
|
124
|
+
blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0
|
|
125
|
+
}
|
|
126
|
+
blocks[14] = this.bytes << 3
|
|
127
|
+
blocks[15] = (this.hBytes << 3) | (this.bytes >>> 29)
|
|
128
|
+
this.hash()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private hash() {
|
|
132
|
+
let a: number, b: number, c: number, d: number, bc: number, da: number
|
|
133
|
+
const { blocks } = this
|
|
134
|
+
|
|
135
|
+
if (this.first) {
|
|
136
|
+
a = blocks[0]! - 680876937
|
|
137
|
+
a = (((a << 7) | (a >>> 25)) - 271733879) << 0
|
|
138
|
+
d = (-1732584194 ^ (a & 2004318071)) + blocks[1]! - 117830708
|
|
139
|
+
d = (((d << 12) | (d >>> 20)) + a) << 0
|
|
140
|
+
c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2]! - 1126478375
|
|
141
|
+
c = (((c << 17) | (c >>> 15)) + d) << 0
|
|
142
|
+
b = (a ^ (c & (d ^ a))) + blocks[3]! - 1316259209
|
|
143
|
+
b = (((b << 22) | (b >>> 10)) + c) << 0
|
|
144
|
+
} else {
|
|
145
|
+
a = this.h0
|
|
146
|
+
b = this.h1
|
|
147
|
+
c = this.h2
|
|
148
|
+
d = this.h3
|
|
149
|
+
a += (d ^ (b & (c ^ d))) + blocks[0]! - 680876936
|
|
150
|
+
a = (((a << 7) | (a >>> 25)) + b) << 0
|
|
151
|
+
d += (c ^ (a & (b ^ c))) + blocks[1]! - 389564586
|
|
152
|
+
d = (((d << 12) | (d >>> 20)) + a) << 0
|
|
153
|
+
c += (b ^ (d & (a ^ b))) + blocks[2]! + 606105819
|
|
154
|
+
c = (((c << 17) | (c >>> 15)) + d) << 0
|
|
155
|
+
b += (a ^ (c & (d ^ a))) + blocks[3]! - 1044525330
|
|
156
|
+
b = (((b << 22) | (b >>> 10)) + c) << 0
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
a += (d ^ (b & (c ^ d))) + blocks[4]! - 176418897
|
|
160
|
+
a = (((a << 7) | (a >>> 25)) + b) << 0
|
|
161
|
+
d += (c ^ (a & (b ^ c))) + blocks[5]! + 1200080426
|
|
162
|
+
d = (((d << 12) | (d >>> 20)) + a) << 0
|
|
163
|
+
c += (b ^ (d & (a ^ b))) + blocks[6]! - 1473231341
|
|
164
|
+
c = (((c << 17) | (c >>> 15)) + d) << 0
|
|
165
|
+
b += (a ^ (c & (d ^ a))) + blocks[7]! - 45705983
|
|
166
|
+
b = (((b << 22) | (b >>> 10)) + c) << 0
|
|
167
|
+
a += (d ^ (b & (c ^ d))) + blocks[8]! + 1770035416
|
|
168
|
+
a = (((a << 7) | (a >>> 25)) + b) << 0
|
|
169
|
+
d += (c ^ (a & (b ^ c))) + blocks[9]! - 1958414417
|
|
170
|
+
d = (((d << 12) | (d >>> 20)) + a) << 0
|
|
171
|
+
c += (b ^ (d & (a ^ b))) + blocks[10]! - 42063
|
|
172
|
+
c = (((c << 17) | (c >>> 15)) + d) << 0
|
|
173
|
+
b += (a ^ (c & (d ^ a))) + blocks[11]! - 1990404162
|
|
174
|
+
b = (((b << 22) | (b >>> 10)) + c) << 0
|
|
175
|
+
a += (d ^ (b & (c ^ d))) + blocks[12]! + 1804603682
|
|
176
|
+
a = (((a << 7) | (a >>> 25)) + b) << 0
|
|
177
|
+
d += (c ^ (a & (b ^ c))) + blocks[13]! - 40341101
|
|
178
|
+
d = (((d << 12) | (d >>> 20)) + a) << 0
|
|
179
|
+
c += (b ^ (d & (a ^ b))) + blocks[14]! - 1502002290
|
|
180
|
+
c = (((c << 17) | (c >>> 15)) + d) << 0
|
|
181
|
+
b += (a ^ (c & (d ^ a))) + blocks[15]! + 1236535329
|
|
182
|
+
b = (((b << 22) | (b >>> 10)) + c) << 0
|
|
183
|
+
a += (c ^ (d & (b ^ c))) + blocks[1]! - 165796510
|
|
184
|
+
a = (((a << 5) | (a >>> 27)) + b) << 0
|
|
185
|
+
d += (b ^ (c & (a ^ b))) + blocks[6]! - 1069501632
|
|
186
|
+
d = (((d << 9) | (d >>> 23)) + a) << 0
|
|
187
|
+
c += (a ^ (b & (d ^ a))) + blocks[11]! + 643717713
|
|
188
|
+
c = (((c << 14) | (c >>> 18)) + d) << 0
|
|
189
|
+
b += (d ^ (a & (c ^ d))) + blocks[0]! - 373897302
|
|
190
|
+
b = (((b << 20) | (b >>> 12)) + c) << 0
|
|
191
|
+
a += (c ^ (d & (b ^ c))) + blocks[5]! - 701558691
|
|
192
|
+
a = (((a << 5) | (a >>> 27)) + b) << 0
|
|
193
|
+
d += (b ^ (c & (a ^ b))) + blocks[10]! + 38016083
|
|
194
|
+
d = (((d << 9) | (d >>> 23)) + a) << 0
|
|
195
|
+
c += (a ^ (b & (d ^ a))) + blocks[15]! - 660478335
|
|
196
|
+
c = (((c << 14) | (c >>> 18)) + d) << 0
|
|
197
|
+
b += (d ^ (a & (c ^ d))) + blocks[4]! - 405537848
|
|
198
|
+
b = (((b << 20) | (b >>> 12)) + c) << 0
|
|
199
|
+
a += (c ^ (d & (b ^ c))) + blocks[9]! + 568446438
|
|
200
|
+
a = (((a << 5) | (a >>> 27)) + b) << 0
|
|
201
|
+
d += (b ^ (c & (a ^ b))) + blocks[14]! - 1019803690
|
|
202
|
+
d = (((d << 9) | (d >>> 23)) + a) << 0
|
|
203
|
+
c += (a ^ (b & (d ^ a))) + blocks[3]! - 187363961
|
|
204
|
+
c = (((c << 14) | (c >>> 18)) + d) << 0
|
|
205
|
+
b += (d ^ (a & (c ^ d))) + blocks[8]! + 1163531501
|
|
206
|
+
b = (((b << 20) | (b >>> 12)) + c) << 0
|
|
207
|
+
a += (c ^ (d & (b ^ c))) + blocks[13]! - 1444681467
|
|
208
|
+
a = (((a << 5) | (a >>> 27)) + b) << 0
|
|
209
|
+
d += (b ^ (c & (a ^ b))) + blocks[2]! - 51403784
|
|
210
|
+
d = (((d << 9) | (d >>> 23)) + a) << 0
|
|
211
|
+
c += (a ^ (b & (d ^ a))) + blocks[7]! + 1735328473
|
|
212
|
+
c = (((c << 14) | (c >>> 18)) + d) << 0
|
|
213
|
+
b += (d ^ (a & (c ^ d))) + blocks[12]! - 1926607734
|
|
214
|
+
b = (((b << 20) | (b >>> 12)) + c) << 0
|
|
215
|
+
bc = b ^ c
|
|
216
|
+
a += (bc ^ d) + blocks[5]! - 378558
|
|
217
|
+
a = (((a << 4) | (a >>> 28)) + b) << 0
|
|
218
|
+
d += (bc ^ a) + blocks[8]! - 2022574463
|
|
219
|
+
d = (((d << 11) | (d >>> 21)) + a) << 0
|
|
220
|
+
da = d ^ a
|
|
221
|
+
c += (da ^ b) + blocks[11]! + 1839030562
|
|
222
|
+
c = (((c << 16) | (c >>> 16)) + d) << 0
|
|
223
|
+
b += (da ^ c) + blocks[14]! - 35309556
|
|
224
|
+
b = (((b << 23) | (b >>> 9)) + c) << 0
|
|
225
|
+
bc = b ^ c
|
|
226
|
+
a += (bc ^ d) + blocks[1]! - 1530992060
|
|
227
|
+
a = (((a << 4) | (a >>> 28)) + b) << 0
|
|
228
|
+
d += (bc ^ a) + blocks[4]! + 1272893353
|
|
229
|
+
d = (((d << 11) | (d >>> 21)) + a) << 0
|
|
230
|
+
da = d ^ a
|
|
231
|
+
c += (da ^ b) + blocks[7]! - 155497632
|
|
232
|
+
c = (((c << 16) | (c >>> 16)) + d) << 0
|
|
233
|
+
b += (da ^ c) + blocks[10]! - 1094730640
|
|
234
|
+
b = (((b << 23) | (b >>> 9)) + c) << 0
|
|
235
|
+
bc = b ^ c
|
|
236
|
+
a += (bc ^ d) + blocks[13]! + 681279174
|
|
237
|
+
a = (((a << 4) | (a >>> 28)) + b) << 0
|
|
238
|
+
d += (bc ^ a) + blocks[0]! - 358537222
|
|
239
|
+
d = (((d << 11) | (d >>> 21)) + a) << 0
|
|
240
|
+
da = d ^ a
|
|
241
|
+
c += (da ^ b) + blocks[3]! - 722521979
|
|
242
|
+
c = (((c << 16) | (c >>> 16)) + d) << 0
|
|
243
|
+
b += (da ^ c) + blocks[6]! + 76029189
|
|
244
|
+
b = (((b << 23) | (b >>> 9)) + c) << 0
|
|
245
|
+
bc = b ^ c
|
|
246
|
+
a += (bc ^ d) + blocks[9]! - 640364487
|
|
247
|
+
a = (((a << 4) | (a >>> 28)) + b) << 0
|
|
248
|
+
d += (bc ^ a) + blocks[12]! - 421815835
|
|
249
|
+
d = (((d << 11) | (d >>> 21)) + a) << 0
|
|
250
|
+
da = d ^ a
|
|
251
|
+
c += (da ^ b) + blocks[15]! + 530742520
|
|
252
|
+
c = (((c << 16) | (c >>> 16)) + d) << 0
|
|
253
|
+
b += (da ^ c) + blocks[2]! - 995338651
|
|
254
|
+
b = (((b << 23) | (b >>> 9)) + c) << 0
|
|
255
|
+
a += (c ^ (b | ~d)) + blocks[0]! - 198630844
|
|
256
|
+
a = (((a << 6) | (a >>> 26)) + b) << 0
|
|
257
|
+
d += (b ^ (a | ~c)) + blocks[7]! + 1126891415
|
|
258
|
+
d = (((d << 10) | (d >>> 22)) + a) << 0
|
|
259
|
+
c += (a ^ (d | ~b)) + blocks[14]! - 1416354905
|
|
260
|
+
c = (((c << 15) | (c >>> 17)) + d) << 0
|
|
261
|
+
b += (d ^ (c | ~a)) + blocks[5]! - 57434055
|
|
262
|
+
b = (((b << 21) | (b >>> 11)) + c) << 0
|
|
263
|
+
a += (c ^ (b | ~d)) + blocks[12]! + 1700485571
|
|
264
|
+
a = (((a << 6) | (a >>> 26)) + b) << 0
|
|
265
|
+
d += (b ^ (a | ~c)) + blocks[3]! - 1894986606
|
|
266
|
+
d = (((d << 10) | (d >>> 22)) + a) << 0
|
|
267
|
+
c += (a ^ (d | ~b)) + blocks[10]! - 1051523
|
|
268
|
+
c = (((c << 15) | (c >>> 17)) + d) << 0
|
|
269
|
+
b += (d ^ (c | ~a)) + blocks[1]! - 2054922799
|
|
270
|
+
b = (((b << 21) | (b >>> 11)) + c) << 0
|
|
271
|
+
a += (c ^ (b | ~d)) + blocks[8]! + 1873313359
|
|
272
|
+
a = (((a << 6) | (a >>> 26)) + b) << 0
|
|
273
|
+
d += (b ^ (a | ~c)) + blocks[15]! - 30611744
|
|
274
|
+
d = (((d << 10) | (d >>> 22)) + a) << 0
|
|
275
|
+
c += (a ^ (d | ~b)) + blocks[6]! - 1560198380
|
|
276
|
+
c = (((c << 15) | (c >>> 17)) + d) << 0
|
|
277
|
+
b += (d ^ (c | ~a)) + blocks[13]! + 1309151649
|
|
278
|
+
b = (((b << 21) | (b >>> 11)) + c) << 0
|
|
279
|
+
a += (c ^ (b | ~d)) + blocks[4]! - 145523070
|
|
280
|
+
a = (((a << 6) | (a >>> 26)) + b) << 0
|
|
281
|
+
d += (b ^ (a | ~c)) + blocks[11]! - 1120210379
|
|
282
|
+
d = (((d << 10) | (d >>> 22)) + a) << 0
|
|
283
|
+
c += (a ^ (d | ~b)) + blocks[2]! + 718787259
|
|
284
|
+
c = (((c << 15) | (c >>> 17)) + d) << 0
|
|
285
|
+
b += (d ^ (c | ~a)) + blocks[9]! - 343485551
|
|
286
|
+
b = (((b << 21) | (b >>> 11)) + c) << 0
|
|
287
|
+
|
|
288
|
+
if (this.first) {
|
|
289
|
+
this.h0 = (a + 1732584193) << 0
|
|
290
|
+
this.h1 = (b - 271733879) << 0
|
|
291
|
+
this.h2 = (c - 1732584194) << 0
|
|
292
|
+
this.h3 = (d + 271733878) << 0
|
|
293
|
+
this.first = false
|
|
294
|
+
} else {
|
|
295
|
+
this.h0 = (this.h0 + a) << 0
|
|
296
|
+
this.h1 = (this.h1 + b) << 0
|
|
297
|
+
this.h2 = (this.h2 + c) << 0
|
|
298
|
+
this.h3 = (this.h3 + d) << 0
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
hex() {
|
|
303
|
+
this.finalize()
|
|
304
|
+
|
|
305
|
+
const { h0, h1, h2, h3 } = this
|
|
306
|
+
const HEX_CHARS = '0123456789abcdef'.split('')
|
|
307
|
+
return (
|
|
308
|
+
// prettier-ignore
|
|
309
|
+
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
|
310
|
+
HEX_CHARS[(h0 >> 4) & 0x0f] + HEX_CHARS[h0 & 0x0f]! + HEX_CHARS[(h0 >> 12) & 0x0f] + HEX_CHARS[(h0 >> 8) & 0x0f] + HEX_CHARS[(h0 >> 20) & 0x0f] +
|
|
311
|
+
HEX_CHARS[(h0 >> 16) & 0x0f] + HEX_CHARS[(h0 >> 28) & 0x0f] + HEX_CHARS[(h0 >> 24) & 0x0f] + HEX_CHARS[(h1 >> 4) & 0x0f] + HEX_CHARS[h1 & 0x0f] +
|
|
312
|
+
HEX_CHARS[(h1 >> 12) & 0x0f] + HEX_CHARS[(h1 >> 8) & 0x0f] + HEX_CHARS[(h1 >> 20) & 0x0f] + HEX_CHARS[(h1 >> 16) & 0x0f] + HEX_CHARS[(h1 >> 28) & 0x0f] +
|
|
313
|
+
HEX_CHARS[(h1 >> 24) & 0x0f] + HEX_CHARS[(h2 >> 4) & 0x0f] + HEX_CHARS[h2 & 0x0f] + HEX_CHARS[(h2 >> 12) & 0x0f] + HEX_CHARS[(h2 >> 8) & 0x0f] +
|
|
314
|
+
HEX_CHARS[(h2 >> 20) & 0x0f] + HEX_CHARS[(h2 >> 16) & 0x0f] + HEX_CHARS[(h2 >> 28) & 0x0f] + HEX_CHARS[(h2 >> 24) & 0x0f] + HEX_CHARS[(h3 >> 4) & 0x0f] +
|
|
315
|
+
HEX_CHARS[h3 & 0x0f] + HEX_CHARS[(h3 >> 12) & 0x0f] + HEX_CHARS[(h3 >> 8) & 0x0f] + HEX_CHARS[(h3 >> 20) & 0x0f] + HEX_CHARS[(h3 >> 16) & 0x0f] +
|
|
316
|
+
HEX_CHARS[(h3 >> 28) & 0x0f] + HEX_CHARS[(h3 >> 24) & 0x0f]
|
|
317
|
+
)
|
|
318
|
+
}
|
|
319
|
+
}
|
package/src/url.ts
CHANGED
|
@@ -9,47 +9,43 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import isPlainObject from 'lodash/isPlainObject.js'
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
1.
|
|
23
|
-
2.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
*/
|
|
31
|
-
function parseQuery(url: string, options?: { array?: false, strict?: boolean }): Record<string, string> // prettier-ignore
|
|
32
|
-
function parseQuery(url: string, options: { array: true, strict?: boolean }): Record<string, string | string[]> // prettier-ignore
|
|
12
|
+
/**
|
|
13
|
+
* 从 URL 中解析出 query 对象
|
|
14
|
+
* 注意:不带 ? 号的纯 query 内容需手动加上 ? 再传入。
|
|
15
|
+
*
|
|
16
|
+
* [array]
|
|
17
|
+
* 是否把重复出现的 key 保存为数组(默认不开启)
|
|
18
|
+
* a=1&a=2 => { a: [1,2] }
|
|
19
|
+
*
|
|
20
|
+
* [loose]
|
|
21
|
+
* 是否开启“宽松模式”(默认不开启)
|
|
22
|
+
* 1. hash 里的内容也会被解析,以兼容拼接错误的 URL(把 query 拼到了 hash 后面)。
|
|
23
|
+
* 2. 出现多个 ? 符号时,会把 ? 也当做 & 分隔符(index.html?a=1&b=2?c=3)
|
|
24
|
+
*
|
|
25
|
+
* [decode]
|
|
26
|
+
* 是否对 query 值进行 decode(默认开启)
|
|
27
|
+
*/
|
|
28
|
+
function parseQuery(url: string, options?: { array?: false, loose?: boolean, decode?: boolean }): Record<string, string> // prettier-ignore
|
|
29
|
+
function parseQuery(url: string, options: { array: true, loose?: boolean, decode?: boolean }): Record<string, string | string[]> // prettier-ignore
|
|
33
30
|
function parseQuery(
|
|
34
31
|
url: string,
|
|
35
|
-
options?: { array?: boolean;
|
|
32
|
+
options?: { array?: boolean; loose?: boolean; decode?: boolean }
|
|
36
33
|
): Record<string, string | string[]> {
|
|
37
|
-
|
|
38
|
-
const { array = false, strict = false } = options ?? {}
|
|
34
|
+
const { array = false, loose = false, decode = true } = options ?? {}
|
|
39
35
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
// 正常状态下,将仅剩 a=1&b=1(即不会再有 ? 和 #);loose 模型下,可能为 a=1&b=2#c=3?d=4
|
|
37
|
+
const queryString = (loose ? /(\?|#)(.+)/ : /(\?)(.+?)(#|$)/).exec(url)?.[2] ?? ''
|
|
38
|
+
if (!queryString) return {}
|
|
43
39
|
|
|
44
40
|
const query: { [name: string]: string | string[] } = {}
|
|
45
41
|
const reg = /([^#?&]*)=([^#?&]*)/g
|
|
46
42
|
let re = reg.exec(queryString)
|
|
47
43
|
while (re) {
|
|
48
|
-
const [name,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
const [name, rawValue] = [re[1]!, re[2]!] as [string, string]
|
|
45
|
+
const value = decode ? safeDecode(rawValue) : rawValue
|
|
46
|
+
if (array && query[name] !== undefined) {
|
|
47
|
+
const prev = query[name]!
|
|
48
|
+
query[name] = Array.isArray(prev) ? [...prev, value] : [prev, value]
|
|
53
49
|
} else {
|
|
54
50
|
query[name] = value
|
|
55
51
|
}
|
|
@@ -59,35 +55,35 @@ function parseQuery(
|
|
|
59
55
|
}
|
|
60
56
|
export { parseQuery }
|
|
61
57
|
|
|
62
|
-
/**
|
|
63
|
-
* 取 query 中指定参数的值
|
|
64
|
-
* - 参数存在,返回参数值(可能是空字符串);不存在返回 null
|
|
65
|
-
* - 解析 query 固定基于 parseQuery() 的 { array: false, strict: false } 规则
|
|
66
|
-
* - 和 parseQuery() 一样,url 可以根据需要传 location.href/search/hash
|
|
67
|
-
*/
|
|
68
|
-
export function getQueryParam(name: string, url: string): string | null {
|
|
69
|
-
const query = parseQuery(url)
|
|
70
|
-
return typeof query[name] === 'string' ? query[name]! : null
|
|
71
|
-
}
|
|
72
|
-
|
|
73
58
|
/**
|
|
74
59
|
* 把对象合并成 query string。
|
|
75
|
-
*
|
|
60
|
+
* - 支持字符串、数值、布尔值、数组。
|
|
61
|
+
* - 布尔值会替换成 0 和 1。
|
|
62
|
+
* - 数组会多次赋值:{ a: [1,2,3] } => 'a=1&a=2&a=3',不支持嵌套数组
|
|
63
|
+
* - encode 为 true 时会对 value 执行 encodeURIComponent(默认为 true)
|
|
76
64
|
*/
|
|
77
65
|
type StringifyVal = string | number | boolean
|
|
78
|
-
|
|
66
|
+
type StringifyQuery = { [key: string]: StringifyVal | StringifyVal[] | undefined }
|
|
67
|
+
export function stringifyQuery(obj: StringifyQuery, encode = true) {
|
|
79
68
|
if (!isPlainObject(obj)) return ''
|
|
80
69
|
return (
|
|
81
70
|
Object.entries(obj)
|
|
82
71
|
// 过滤值为 undefined 的项目,使其完全不出现在最终的 query 中
|
|
83
72
|
.filter((entry): entry is [string, StringifyVal | StringifyVal[]] => entry[1] !== undefined)
|
|
84
|
-
.map(([name, value]) => stringifyQueryItem(name, value))
|
|
73
|
+
.map(([name, value]) => stringifyQueryItem(name, value, encode))
|
|
85
74
|
.join('&')
|
|
86
75
|
)
|
|
87
76
|
}
|
|
88
|
-
function stringifyQueryItem(
|
|
77
|
+
function stringifyQueryItem(
|
|
78
|
+
name: string,
|
|
79
|
+
value: StringifyVal | StringifyVal[],
|
|
80
|
+
encode: boolean
|
|
81
|
+
): string {
|
|
89
82
|
if (Array.isArray(value))
|
|
90
|
-
return value.map(subValue => stringifyQueryItem(
|
|
83
|
+
return value.map(subValue => stringifyQueryItem(name, subValue, encode)).join('&')
|
|
84
|
+
if (typeof value === 'boolean') value = value ? '1' : '0'
|
|
85
|
+
if (typeof value === 'number') value = value.toString()
|
|
86
|
+
if (encode) value = encodeURIComponent(value)
|
|
91
87
|
return `${name}=${value}`
|
|
92
88
|
}
|
|
93
89
|
|
|
@@ -96,6 +92,7 @@ function stringifyQueryItem(name: string, value: StringifyVal | StringifyVal[]):
|
|
|
96
92
|
*
|
|
97
93
|
* bare 为 true,则 search 不带 '?',hash 不带 '#'
|
|
98
94
|
* 否则和 location.search / hash 一样
|
|
95
|
+
* (默认为 true)
|
|
99
96
|
*/
|
|
100
97
|
export function splitUrl(url: string, bare = true): { base: string; search: string; hash: string } {
|
|
101
98
|
let hashIndex = url.indexOf('#')
|
|
@@ -114,16 +111,12 @@ export function splitUrl(url: string, bare = true): { base: string; search: stri
|
|
|
114
111
|
}
|
|
115
112
|
|
|
116
113
|
/**
|
|
117
|
-
*
|
|
114
|
+
* 把 query 和 hash 内容合并到 url 上
|
|
118
115
|
*
|
|
119
116
|
* query object 与现有 search 合并,替换同名项(值为数组的,用新数组代替老的,不会合并数组)
|
|
120
|
-
* hash string
|
|
117
|
+
* hash string 带不带开头的 '#' 皆可。会代替 url 已有的 hash。
|
|
121
118
|
*/
|
|
122
|
-
export function combineUrl(
|
|
123
|
-
origUrl: string,
|
|
124
|
-
query: Record<string, string | string[]> = {},
|
|
125
|
-
hash: string = ''
|
|
126
|
-
) {
|
|
119
|
+
export function combineUrl(origUrl: string, query: StringifyQuery = {}, hash: string = '') {
|
|
127
120
|
if (hash.startsWith('#')) hash = hash.slice(1)
|
|
128
121
|
|
|
129
122
|
// 拆分原 url 的 search、hash
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { success, failed } from '../lang/index.js'
|
|
2
|
+
import { Validator } from './base.js'
|
|
3
|
+
|
|
4
|
+
/** 验证元素数量任意、元素类型相同的数组 */
|
|
5
|
+
export type ArrayOptions = {
|
|
6
|
+
/** 验证数组各元素 */
|
|
7
|
+
item: Validator
|
|
8
|
+
/** 数组最小长度 */
|
|
9
|
+
min?: number
|
|
10
|
+
/** 数组最大长度 */
|
|
11
|
+
max?: number
|
|
12
|
+
/** 是否对数组元素进行去重 @defaults false */
|
|
13
|
+
unique?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** 验证元素数量固定、类型可以不同的数组 */
|
|
17
|
+
export type TupleOptions = {
|
|
18
|
+
/** 验证数组各元素(validator 与元素一一对应) */
|
|
19
|
+
tuple: Validator[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class ArrayValidator extends Validator<ArrayOptions | TupleOptions> {
|
|
23
|
+
validate(field: string, value: unknown) {
|
|
24
|
+
const superResult = super.validate(field, value)
|
|
25
|
+
if (!superResult.success) return superResult
|
|
26
|
+
|
|
27
|
+
value = superResult.data
|
|
28
|
+
if (value === null || value === undefined) return superResult
|
|
29
|
+
const opt = this.options
|
|
30
|
+
|
|
31
|
+
if (!Array.isArray(value)) return failed(`${field} should be an array`)
|
|
32
|
+
|
|
33
|
+
let formatted = []
|
|
34
|
+
if ('item' in opt) {
|
|
35
|
+
if (typeof opt.min === 'number' && value.length < opt.min)
|
|
36
|
+
return failed(`array ${field}'s length should >= ${opt.min}`)
|
|
37
|
+
|
|
38
|
+
if (typeof opt.max === 'number' && value.length > opt.max)
|
|
39
|
+
return failed(`array ${field}'s length should <= ${opt.max}`)
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < value.length; i++) {
|
|
42
|
+
const itemResult = opt.item.validate(`${field}[${i}]`, value[i])
|
|
43
|
+
if (itemResult.success) formatted.push(itemResult.data)
|
|
44
|
+
else return itemResult
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (opt.unique === true) formatted = [...new Set(formatted)]
|
|
48
|
+
} else {
|
|
49
|
+
if (value.length > opt.tuple.length)
|
|
50
|
+
return failed(`${field} should be a tuple with ${opt.tuple.length} items`)
|
|
51
|
+
|
|
52
|
+
// 这种情况不能遍历 value,因为它的长度可能小于 opt.tuple
|
|
53
|
+
for (let i = 0; i < opt.tuple.length; i++) {
|
|
54
|
+
const itemResult = opt.tuple[i]!.validate(`${field}[${i}]`, value[i])
|
|
55
|
+
if (itemResult.success) formatted.push(itemResult.data)
|
|
56
|
+
else return itemResult
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return success(formatted)
|
|
61
|
+
}
|
|
62
|
+
}
|