@anjianshi/utils 2.5.0 → 2.6.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/README.md +10 -0
- package/eslint.config.cjs +33 -0
- package/package.json +26 -15
- package/publish-prepare.cjs +16 -0
- package/src/env-browser/device.ts +62 -0
- package/src/env-browser/global.ts +21 -0
- package/src/env-browser/load-script.ts +13 -0
- package/src/env-browser/logging.ts +58 -0
- package/src/env-browser/manage-vconsole.ts +54 -0
- package/src/env-node/crypto-random.ts +30 -0
- package/src/env-node/fs.ts +50 -0
- package/src/env-node/index.ts +6 -0
- package/src/env-node/logging/handlers.ts +190 -0
- package/src/env-node/logging/index.ts +16 -0
- package/src/env-node/safe-request.ts +66 -0
- package/src/env-react/emotion.tsx +42 -0
- package/src/env-service/controllers.ts +93 -0
- package/src/env-service/env-reader.ts +141 -0
- package/src/env-service/index.ts +6 -0
- package/src/env-service/prisma/adapt-logging.ts +39 -0
- package/src/env-service/prisma/extensions/exist.ts +21 -0
- package/src/env-service/prisma/extensions/find-and-count.ts +24 -0
- package/src/env-service/prisma/extensions/soft-delete.ts +162 -0
- package/src/env-service/prisma/extensions/with-transaction.ts +65 -0
- package/src/env-service/prisma/index.ts +6 -0
- package/src/env-service/prisma/transaction-contexted.ts +80 -0
- package/src/env-service/redis-cache.ts +142 -0
- package/src/env-service/tasks.ts +45 -0
- package/src/index.ts +3 -0
- package/src/init-dayjs.ts +8 -0
- package/src/lang/async.ts +47 -0
- package/src/lang/color.ts +119 -0
- package/src/lang/index.ts +7 -0
- package/src/lang/may-success.ts +57 -0
- package/src/lang/object.ts +39 -0
- package/src/lang/random.ts +25 -0
- package/src/lang/string.ts +95 -0
- package/src/lang/time.ts +19 -0
- package/{lang/types.d.ts → src/lang/types.ts} +43 -23
- package/src/logging/adapt.ts +49 -0
- package/src/logging/formatters.ts +23 -0
- package/src/logging/index.ts +106 -0
- package/src/md5.ts +318 -0
- package/src/url.ts +185 -0
- package/src/validators/array.ts +97 -0
- package/src/validators/base.ts +145 -0
- package/src/validators/boolean.ts +21 -0
- package/src/validators/datetime.ts +39 -0
- package/src/validators/factory.ts +244 -0
- package/src/validators/index.ts +9 -0
- package/src/validators/number.ts +54 -0
- package/src/validators/object.ts +101 -0
- package/src/validators/one-of.ts +33 -0
- package/src/validators/string.ts +72 -0
- package/env-browser/device.d.ts +0 -24
- package/env-browser/device.js +0 -50
- package/env-browser/global.d.ts +0 -10
- package/env-browser/global.js +0 -15
- package/env-browser/load-script.d.ts +0 -5
- package/env-browser/load-script.js +0 -13
- package/env-browser/logging.d.ts +0 -18
- package/env-browser/logging.js +0 -49
- package/env-browser/manage-vconsole.d.ts +0 -16
- package/env-browser/manage-vconsole.js +0 -38
- package/env-node/crypto-random.d.ts +0 -13
- package/env-node/crypto-random.js +0 -28
- package/env-node/fs.d.ts +0 -19
- package/env-node/fs.js +0 -48
- package/env-node/index.d.ts +0 -5
- package/env-node/index.js +0 -5
- package/env-node/logging/handlers.d.ts +0 -58
- package/env-node/logging/handlers.js +0 -154
- package/env-node/logging/index.d.ts +0 -11
- package/env-node/logging/index.js +0 -14
- package/env-react/emotion.d.ts +0 -20
- package/env-react/emotion.jsx +0 -34
- package/env-service/controllers.d.ts +0 -30
- package/env-service/controllers.js +0 -41
- package/env-service/env-reader.d.ts +0 -55
- package/env-service/env-reader.js +0 -79
- package/env-service/index.d.ts +0 -6
- package/env-service/index.js +0 -6
- package/env-service/prisma/adapt-logging.d.ts +0 -21
- package/env-service/prisma/adapt-logging.js +0 -30
- package/env-service/prisma/extensions/exist.d.ts +0 -10
- package/env-service/prisma/extensions/exist.js +0 -16
- package/env-service/prisma/extensions/find-and-count.d.ts +0 -7
- package/env-service/prisma/extensions/find-and-count.js +0 -19
- package/env-service/prisma/extensions/soft-delete.d.ts +0 -52
- package/env-service/prisma/extensions/soft-delete.js +0 -123
- package/env-service/prisma/extensions/with-transaction.d.ts +0 -9
- package/env-service/prisma/extensions/with-transaction.js +0 -54
- package/env-service/prisma/index.d.ts +0 -6
- package/env-service/prisma/index.js +0 -6
- package/env-service/prisma/transaction-contexted.d.ts +0 -11
- package/env-service/prisma/transaction-contexted.js +0 -52
- package/env-service/redis-cache.d.ts +0 -39
- package/env-service/redis-cache.js +0 -116
- package/env-service/tasks.d.ts +0 -12
- package/env-service/tasks.js +0 -37
- package/index.d.ts +0 -3
- package/index.js +0 -3
- package/init-dayjs.d.ts +0 -2
- package/init-dayjs.js +0 -7
- package/lang/async.d.ts +0 -19
- package/lang/async.js +0 -34
- package/lang/index.d.ts +0 -7
- package/lang/index.js +0 -7
- package/lang/may-success.d.ts +0 -40
- package/lang/may-success.js +0 -27
- package/lang/object.d.ts +0 -5
- package/lang/object.js +0 -31
- package/lang/random.d.ts +0 -13
- package/lang/random.js +0 -24
- package/lang/string.d.ts +0 -29
- package/lang/string.js +0 -92
- package/lang/time.d.ts +0 -10
- package/lang/time.js +0 -18
- package/lang/types.js +0 -28
- package/logging/adapt.d.ts +0 -10
- package/logging/adapt.js +0 -43
- package/logging/formatters.d.ts +0 -10
- package/logging/formatters.js +0 -22
- package/logging/index.d.ts +0 -45
- package/logging/index.js +0 -90
- package/md5.d.ts +0 -30
- package/md5.js +0 -308
- package/url.d.ts +0 -77
- package/url.js +0 -149
- package/validators/array.d.ts +0 -30
- package/validators/array.js +0 -47
- package/validators/base.d.ts +0 -82
- package/validators/base.js +0 -42
- package/validators/boolean.d.ts +0 -3
- package/validators/boolean.js +0 -22
- package/validators/factory.d.ts +0 -66
- package/validators/factory.js +0 -109
- package/validators/index.d.ts +0 -8
- package/validators/index.js +0 -8
- package/validators/number.d.ts +0 -19
- package/validators/number.js +0 -26
- package/validators/object.d.ts +0 -28
- package/validators/object.js +0 -49
- package/validators/oneOf.d.ts +0 -10
- package/validators/oneOf.js +0 -15
- package/validators/string.d.ts +0 -22
- package/validators/string.js +0 -35
package/src/lang/time.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 时间处理相关函数
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 返回指定时间长度的 毫秒数
|
|
7
|
+
*/
|
|
8
|
+
export function daysMS(n: number) {
|
|
9
|
+
return hoursMS(n * 24)
|
|
10
|
+
}
|
|
11
|
+
export function hoursMS(n: number) {
|
|
12
|
+
return minutesMS(n * 60)
|
|
13
|
+
}
|
|
14
|
+
export function minutesMS(n: number) {
|
|
15
|
+
return secondsMS(n * 60)
|
|
16
|
+
}
|
|
17
|
+
export function secondsMS(n: number) {
|
|
18
|
+
return n * 1000
|
|
19
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 对类型系统的辅助、补充
|
|
3
3
|
*/
|
|
4
|
+
|
|
4
5
|
/**
|
|
5
6
|
* 解决 TypeScript 中,数组字面量 [1, 'a'] 无法自动识别为 tuple 的问题
|
|
6
7
|
*
|
|
@@ -11,17 +12,22 @@
|
|
|
11
12
|
* https://github.com/microsoft/TypeScript/issues/27179
|
|
12
13
|
* https://github.com/microsoft/TypeScript/issues/16656
|
|
13
14
|
*/
|
|
14
|
-
export
|
|
15
|
+
export function tuple<T extends unknown[]>(...elements: T) {
|
|
16
|
+
return elements
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
/** 将一个对象中的指定 key 设为必须的 */
|
|
16
|
-
export type RequiredFields<T, K extends keyof T> = Omit<T, K> & Pick<Required<T>, K
|
|
20
|
+
export type RequiredFields<T, K extends keyof T> = Omit<T, K> & Pick<Required<T>, K>
|
|
21
|
+
|
|
17
22
|
/** 将一个对象中的指定 key 设为非必须的 */
|
|
18
|
-
export type OptionalFields<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K
|
|
23
|
+
export type OptionalFields<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
|
|
24
|
+
|
|
19
25
|
/** 用 ReplaceT 中的字段定义代替 T 中的 */
|
|
20
|
-
export type ReplaceFields<T, ReplaceT> = Omit<T, keyof ReplaceT> & ReplaceT
|
|
26
|
+
export type ReplaceFields<T, ReplaceT> = Omit<T, keyof ReplaceT> & ReplaceT
|
|
27
|
+
|
|
21
28
|
/** 获取一个对象所有 value 的集合 */
|
|
22
|
-
export type ValueOf<T> = T extends {
|
|
23
|
-
|
|
24
|
-
} ? U : never;
|
|
29
|
+
export type ValueOf<T> = T extends { [_ in keyof T]: infer U } ? U : never
|
|
30
|
+
|
|
25
31
|
/**
|
|
26
32
|
* 获取指定类型的 key 的集合
|
|
27
33
|
* 可以解决 keyof 无法正确获取继承了 plain object interface 的类型的 key 的问题
|
|
@@ -32,32 +38,46 @@ export type ValueOf<T> = T extends {
|
|
|
32
38
|
* KnownKeys<MyType> // 'a' | 'b'
|
|
33
39
|
*/
|
|
34
40
|
export type KnownKeys<T> = ValueOf<{
|
|
35
|
-
|
|
36
|
-
}
|
|
41
|
+
[K in keyof T]: string extends K ? never : number extends K ? never : K
|
|
42
|
+
}>
|
|
43
|
+
|
|
37
44
|
/** 排除对象中指定类型的项目 */
|
|
38
|
-
export type ExcludePropertiesOfType<T, ExcludeValueT> = Pick<
|
|
39
|
-
|
|
40
|
-
}[keyof T]
|
|
45
|
+
export type ExcludePropertiesOfType<T, ExcludeValueT> = Pick<
|
|
46
|
+
T,
|
|
47
|
+
{ [K in keyof T]: T[K] extends ExcludeValueT ? never : K }[keyof T]
|
|
48
|
+
>
|
|
49
|
+
|
|
41
50
|
/**
|
|
42
51
|
* 生成不包含指定 key 的类型
|
|
43
52
|
* 与 Omit<T, Keys> 的区别是
|
|
44
53
|
*/
|
|
45
|
-
export type ExcludeKeys<T, ExcludeKeys> = Pick<
|
|
46
|
-
|
|
47
|
-
}[keyof T]
|
|
54
|
+
export type ExcludeKeys<T, ExcludeKeys> = Pick<
|
|
55
|
+
T,
|
|
56
|
+
{ [K in keyof T]: K extends ExcludeKeys ? never : K }[keyof T]
|
|
57
|
+
>
|
|
58
|
+
|
|
48
59
|
/** 排除对象的方法(仅保留属性) */
|
|
49
|
-
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
61
|
+
export type ExcluceMethods<T> = ExcludePropertiesOfType<T, Function>
|
|
62
|
+
|
|
50
63
|
/**
|
|
51
64
|
* 确认变量是否有值
|
|
52
65
|
* 注意:空字符串和数字 0 也会判定为没有值
|
|
53
66
|
*/
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
67
|
+
function truthy(
|
|
68
|
+
value: string | number | boolean | null | undefined,
|
|
69
|
+
): value is string | number | true
|
|
70
|
+
function truthy<T>(
|
|
71
|
+
value: T | string | number | boolean | null | undefined,
|
|
72
|
+
): value is T | string | number | true
|
|
73
|
+
function truthy<T>(value: T | string | number | boolean | null | undefined) {
|
|
74
|
+
return value !== null && value !== undefined && value !== '' && value !== 0 && value !== false
|
|
75
|
+
}
|
|
76
|
+
export { truthy }
|
|
77
|
+
|
|
57
78
|
/** 定义 JSON 数据 */
|
|
58
|
-
export type JSONData = number | boolean | string | null | JSONData[] | {
|
|
59
|
-
|
|
60
|
-
};
|
|
79
|
+
export type JSONData = number | boolean | string | null | JSONData[] | { [key: string]: JSONData }
|
|
80
|
+
|
|
61
81
|
/**
|
|
62
82
|
* 有些场景不适合用 undefined 判断一个变量是否被赋值(例如它允许被赋值成 undefined)
|
|
63
83
|
* 此时可以用这个 symbol 来做判断。
|
|
@@ -65,4 +85,4 @@ export type JSONData = number | boolean | string | null | JSONData[] | {
|
|
|
65
85
|
* if (value === noValue) console.log('未赋值')
|
|
66
86
|
* else console.log('已赋值', value)
|
|
67
87
|
*/
|
|
68
|
-
export
|
|
88
|
+
export const noValue = Symbol('no-value')
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { getLogger, type Logger } from './index.js'
|
|
2
|
+
|
|
3
|
+
interface Debug {
|
|
4
|
+
enable: (namespaces: string) => void
|
|
5
|
+
log: (...args: any[]) => any // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 适配 debug package
|
|
10
|
+
*/
|
|
11
|
+
export function adaptDebugLib(debugLib: Debug, enable = '', logger?: Logger) {
|
|
12
|
+
// 不在 localStorage 里记录 debugLib enable 状态,
|
|
13
|
+
// 以解决 web worker 里读不到 localStorage 而无法启用 debugLib 日志的问题
|
|
14
|
+
const emulate = {
|
|
15
|
+
storage: {
|
|
16
|
+
data: {} as Record<string, string>,
|
|
17
|
+
getItem(name: string) {
|
|
18
|
+
return emulate.storage.data[name]
|
|
19
|
+
},
|
|
20
|
+
setItem(name: string, value: string) {
|
|
21
|
+
emulate.storage.data[name] = value
|
|
22
|
+
},
|
|
23
|
+
removeItem(name: string) {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
25
|
+
delete emulate.storage.data[name]
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
save(namespaces: string) {
|
|
29
|
+
if (namespaces) emulate.storage.setItem('debug', namespaces)
|
|
30
|
+
else emulate.storage.removeItem('debug')
|
|
31
|
+
},
|
|
32
|
+
load() {
|
|
33
|
+
return emulate.storage.getItem('debug')
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
Object.assign(debugLib, emulate)
|
|
37
|
+
|
|
38
|
+
// 将 debugLib 日志转发给 logger
|
|
39
|
+
if (!logger) logger = getLogger('3rd-library')
|
|
40
|
+
debugLib.log = logger.debug.bind(logger)
|
|
41
|
+
|
|
42
|
+
if (enable) {
|
|
43
|
+
// 有些库(例如 prisma)重新实现了自己的 debug 库,且模仿 debug 也读取 DEBUG 环境变量。
|
|
44
|
+
// 这里除了设置 debug 库,顺便也适配这些遵循 debug 库模式的自定义库。
|
|
45
|
+
process.env.DEBUG = enable
|
|
46
|
+
|
|
47
|
+
debugLib.enable(enable)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 日志常用数据的格式化函数
|
|
3
|
+
*/
|
|
4
|
+
import { type LogInfo, LogLevel } from './index.js'
|
|
5
|
+
|
|
6
|
+
const formatters = {
|
|
7
|
+
time(info: LogInfo) {
|
|
8
|
+
return info.time.format('HH:mm:ss.SSS')
|
|
9
|
+
},
|
|
10
|
+
datetime(info: LogInfo) {
|
|
11
|
+
return info.time.format('YY-MM-DD HH:mm:ss.SSS')
|
|
12
|
+
},
|
|
13
|
+
level(info: LogInfo) {
|
|
14
|
+
const map = {
|
|
15
|
+
[LogLevel.Debug]: 'debug',
|
|
16
|
+
[LogLevel.Info]: 'info',
|
|
17
|
+
[LogLevel.Warning]: 'warn',
|
|
18
|
+
[LogLevel.Error]: 'error',
|
|
19
|
+
}
|
|
20
|
+
return map[info.level]
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
export default formatters
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import dayjs, { type Dayjs } from 'dayjs'
|
|
2
|
+
export { default as formatters } from './formatters.js'
|
|
3
|
+
export * from './adapt.js'
|
|
4
|
+
import { initDayJs } from '../init-dayjs.js'
|
|
5
|
+
|
|
6
|
+
// 引入 logging 库会自动初始化 dayjs
|
|
7
|
+
initDayJs()
|
|
8
|
+
|
|
9
|
+
export enum LogLevel {
|
|
10
|
+
Debug = 1,
|
|
11
|
+
Info = 2,
|
|
12
|
+
Warning = 3,
|
|
13
|
+
Error = 4,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const logLevelMap: Record<string, LogLevel> = {
|
|
17
|
+
debug: LogLevel.Debug,
|
|
18
|
+
info: LogLevel.Info,
|
|
19
|
+
warn: LogLevel.Warning,
|
|
20
|
+
warning: LogLevel.Warning,
|
|
21
|
+
err: LogLevel.Error,
|
|
22
|
+
error: LogLevel.Error,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface LogInfo {
|
|
26
|
+
logger: string // logger name;有多级 logger 的情况下,这是最初的 logger 名称
|
|
27
|
+
level: LogLevel
|
|
28
|
+
time: Dayjs
|
|
29
|
+
args: unknown[] // log content
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class LogHandler {
|
|
33
|
+
log(info: LogInfo) {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class Logger {
|
|
37
|
+
level = LogLevel.Info
|
|
38
|
+
handlers = new Set<LogHandler>()
|
|
39
|
+
|
|
40
|
+
constructor(
|
|
41
|
+
public name = '',
|
|
42
|
+
public base: Logger | null = null, // 指定上级 logger,当前 logger 记录的日志也会传递给上级
|
|
43
|
+
) {}
|
|
44
|
+
|
|
45
|
+
static getRealLevel(raw: LogLevel | string) {
|
|
46
|
+
if (typeof raw === 'string') {
|
|
47
|
+
raw = raw.toLowerCase()
|
|
48
|
+
if (logLevelMap[raw] === undefined) throw new Error('Not supported log level: ' + raw)
|
|
49
|
+
return logLevelMap[raw]!
|
|
50
|
+
}
|
|
51
|
+
return raw
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
setLevel(level: LogLevel | string) {
|
|
55
|
+
this.level = Logger.getRealLevel(level)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
addHandler(handler: LogHandler) {
|
|
59
|
+
this.handlers.add(handler)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 创建一个以当前 logger 为 base 的 child logger
|
|
64
|
+
*/
|
|
65
|
+
getChild(name: string) {
|
|
66
|
+
const fullname = this.name ? `${this.name}/${name}` : name
|
|
67
|
+
type Constructor = new (...args: ConstructorParameters<typeof Logger>) => Logger
|
|
68
|
+
// 这里加上 `as this` 才能让 TypeScript 判定,对继承了 Logger 的类调用此方法时,返回的是那个类而不是原始的 Logger 类的实例
|
|
69
|
+
return new (this.constructor as Constructor)(fullname, this) as this
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
log(level: LogLevel | string, args: unknown[]) {
|
|
73
|
+
level = Logger.getRealLevel(level)
|
|
74
|
+
this.logByInfo({ logger: this.name, level, time: dayjs(), args })
|
|
75
|
+
}
|
|
76
|
+
protected logByInfo(info: LogInfo) {
|
|
77
|
+
if (this.base) this.base.logByInfo(info)
|
|
78
|
+
if (this.level > info.level) return
|
|
79
|
+
for (const handler of this.handlers) {
|
|
80
|
+
handler.log(info)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
debug(...args: any[]) {
|
|
85
|
+
this.log(LogLevel.Debug, args)
|
|
86
|
+
}
|
|
87
|
+
info(...args: any[]) {
|
|
88
|
+
this.log(LogLevel.Info, args)
|
|
89
|
+
}
|
|
90
|
+
warn(...args: any[]) {
|
|
91
|
+
this.log(LogLevel.Warning, args)
|
|
92
|
+
}
|
|
93
|
+
error(...args: any[]) {
|
|
94
|
+
this.log(LogLevel.Error, args)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 提供一套默认配置好的 logger
|
|
100
|
+
*/
|
|
101
|
+
const defaultLogger = new Logger()
|
|
102
|
+
export { defaultLogger as logger }
|
|
103
|
+
|
|
104
|
+
export function getLogger(name: string) {
|
|
105
|
+
return defaultLogger.getChild(name)
|
|
106
|
+
}
|
package/src/md5.ts
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/* eslint-disable no-multi-assign */
|
|
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
|
+
HEX_CHARS[(h0 >> 4) & 0x0f]! + HEX_CHARS[h0 & 0x0f]! + HEX_CHARS[(h0 >> 12) & 0x0f]! + HEX_CHARS[(h0 >> 8) & 0x0f]! + HEX_CHARS[(h0 >> 20) & 0x0f]! +
|
|
310
|
+
HEX_CHARS[(h0 >> 16) & 0x0f]! + HEX_CHARS[(h0 >> 28) & 0x0f]! + HEX_CHARS[(h0 >> 24) & 0x0f]! + HEX_CHARS[(h1 >> 4) & 0x0f]! + HEX_CHARS[h1 & 0x0f]! +
|
|
311
|
+
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]! +
|
|
312
|
+
HEX_CHARS[(h1 >> 24) & 0x0f]! + HEX_CHARS[(h2 >> 4) & 0x0f]! + HEX_CHARS[h2 & 0x0f]! + HEX_CHARS[(h2 >> 12) & 0x0f]! + HEX_CHARS[(h2 >> 8) & 0x0f]! +
|
|
313
|
+
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]! +
|
|
314
|
+
HEX_CHARS[h3 & 0x0f]! + HEX_CHARS[(h3 >> 12) & 0x0f]! + HEX_CHARS[(h3 >> 8) & 0x0f]! + HEX_CHARS[(h3 >> 20) & 0x0f]! + HEX_CHARS[(h3 >> 16) & 0x0f]! +
|
|
315
|
+
HEX_CHARS[(h3 >> 28) & 0x0f]! + HEX_CHARS[(h3 >> 24) & 0x0f]!
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
}
|