@anjianshi/utils 2.7.0 → 2.8.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.
Files changed (153) hide show
  1. package/env-browser/device.d.ts +24 -0
  2. package/env-browser/device.js +50 -0
  3. package/env-browser/global.d.ts +10 -0
  4. package/env-browser/global.js +15 -0
  5. package/env-browser/load-script.d.ts +5 -0
  6. package/env-browser/load-script.js +13 -0
  7. package/env-browser/logging.d.ts +18 -0
  8. package/env-browser/logging.js +49 -0
  9. package/env-browser/manage-vconsole.d.ts +16 -0
  10. package/env-browser/manage-vconsole.js +38 -0
  11. package/env-node/crypto-random.d.ts +13 -0
  12. package/env-node/crypto-random.js +28 -0
  13. package/env-node/fs.d.ts +19 -0
  14. package/env-node/fs.js +48 -0
  15. package/env-node/index.d.ts +6 -0
  16. package/env-node/index.js +6 -0
  17. package/env-node/logging/handlers.d.ts +58 -0
  18. package/env-node/logging/handlers.js +154 -0
  19. package/env-node/logging/index.d.ts +11 -0
  20. package/env-node/logging/index.js +14 -0
  21. package/env-node/safe-request.d.ts +26 -0
  22. package/env-node/safe-request.js +40 -0
  23. package/env-react/emotion.d.ts +20 -0
  24. package/env-react/emotion.jsx +34 -0
  25. package/env-service/controllers.d.ts +30 -0
  26. package/env-service/controllers.js +41 -0
  27. package/env-service/env-reader.d.ts +55 -0
  28. package/env-service/env-reader.js +79 -0
  29. package/env-service/index.d.ts +6 -0
  30. package/env-service/index.js +6 -0
  31. package/env-service/prisma/adapt-logging.d.ts +21 -0
  32. package/env-service/prisma/adapt-logging.js +30 -0
  33. package/env-service/prisma/extensions/exist.d.ts +10 -0
  34. package/env-service/prisma/extensions/exist.js +16 -0
  35. package/env-service/prisma/extensions/find-and-count.d.ts +7 -0
  36. package/env-service/prisma/extensions/find-and-count.js +19 -0
  37. package/env-service/prisma/extensions/soft-delete.d.ts +52 -0
  38. package/env-service/prisma/extensions/soft-delete.js +123 -0
  39. package/env-service/prisma/extensions/with-transaction.d.ts +9 -0
  40. package/env-service/prisma/extensions/with-transaction.js +54 -0
  41. package/env-service/prisma/index.d.ts +6 -0
  42. package/env-service/prisma/index.js +6 -0
  43. package/env-service/prisma/transaction-contexted.d.ts +11 -0
  44. package/env-service/prisma/transaction-contexted.js +52 -0
  45. package/env-service/redis-cache.d.ts +39 -0
  46. package/env-service/redis-cache.js +116 -0
  47. package/env-service/tasks.d.ts +12 -0
  48. package/env-service/tasks.js +37 -0
  49. package/index.d.ts +3 -0
  50. package/index.js +3 -0
  51. package/init-dayjs.d.ts +2 -0
  52. package/init-dayjs.js +7 -0
  53. package/lang/async.d.ts +19 -0
  54. package/lang/async.js +34 -0
  55. package/lang/color.d.ts +37 -0
  56. package/lang/color.js +111 -0
  57. package/lang/index.d.ts +7 -0
  58. package/lang/index.js +7 -0
  59. package/lang/may-success.d.ts +40 -0
  60. package/lang/may-success.js +27 -0
  61. package/lang/object.d.ts +12 -0
  62. package/lang/object.js +41 -0
  63. package/lang/random.d.ts +13 -0
  64. package/lang/random.js +24 -0
  65. package/lang/string.d.ts +29 -0
  66. package/lang/string.js +92 -0
  67. package/lang/time.d.ts +10 -0
  68. package/lang/time.js +18 -0
  69. package/{src/lang/types.ts → lang/types.d.ts} +23 -43
  70. package/lang/types.js +28 -0
  71. package/logging/adapt.d.ts +10 -0
  72. package/logging/adapt.js +43 -0
  73. package/logging/formatters.d.ts +10 -0
  74. package/logging/formatters.js +22 -0
  75. package/logging/index.d.ts +45 -0
  76. package/logging/index.js +90 -0
  77. package/md5.d.ts +30 -0
  78. package/md5.js +308 -0
  79. package/package.json +14 -20
  80. package/url.d.ts +77 -0
  81. package/url.js +149 -0
  82. package/validators/array.d.ts +30 -0
  83. package/validators/array.js +47 -0
  84. package/validators/base.d.ts +82 -0
  85. package/validators/base.js +42 -0
  86. package/validators/boolean.d.ts +3 -0
  87. package/validators/boolean.js +22 -0
  88. package/validators/datetime.d.ts +12 -0
  89. package/validators/datetime.js +30 -0
  90. package/validators/factory.d.ts +70 -0
  91. package/validators/factory.js +121 -0
  92. package/validators/index.d.ts +9 -0
  93. package/validators/index.js +9 -0
  94. package/validators/number.d.ts +19 -0
  95. package/validators/number.js +26 -0
  96. package/validators/object.d.ts +28 -0
  97. package/validators/object.js +49 -0
  98. package/validators/one-of.d.ts +10 -0
  99. package/validators/one-of.js +15 -0
  100. package/validators/string.d.ts +22 -0
  101. package/validators/string.js +35 -0
  102. package/README.md +0 -10
  103. package/eslint.config.cjs +0 -33
  104. package/publish-prepare.cjs +0 -16
  105. package/src/env-browser/device.ts +0 -62
  106. package/src/env-browser/global.ts +0 -21
  107. package/src/env-browser/load-script.ts +0 -13
  108. package/src/env-browser/logging.ts +0 -58
  109. package/src/env-browser/manage-vconsole.ts +0 -54
  110. package/src/env-node/crypto-random.ts +0 -30
  111. package/src/env-node/fs.ts +0 -50
  112. package/src/env-node/index.ts +0 -6
  113. package/src/env-node/logging/handlers.ts +0 -190
  114. package/src/env-node/logging/index.ts +0 -16
  115. package/src/env-node/safe-request.ts +0 -66
  116. package/src/env-react/emotion.tsx +0 -42
  117. package/src/env-service/controllers.ts +0 -93
  118. package/src/env-service/env-reader.ts +0 -141
  119. package/src/env-service/index.ts +0 -6
  120. package/src/env-service/prisma/adapt-logging.ts +0 -39
  121. package/src/env-service/prisma/extensions/exist.ts +0 -21
  122. package/src/env-service/prisma/extensions/find-and-count.ts +0 -24
  123. package/src/env-service/prisma/extensions/soft-delete.ts +0 -162
  124. package/src/env-service/prisma/extensions/with-transaction.ts +0 -65
  125. package/src/env-service/prisma/index.ts +0 -6
  126. package/src/env-service/prisma/transaction-contexted.ts +0 -80
  127. package/src/env-service/redis-cache.ts +0 -142
  128. package/src/env-service/tasks.ts +0 -45
  129. package/src/index.ts +0 -3
  130. package/src/init-dayjs.ts +0 -8
  131. package/src/lang/async.ts +0 -47
  132. package/src/lang/color.ts +0 -119
  133. package/src/lang/index.ts +0 -7
  134. package/src/lang/may-success.ts +0 -57
  135. package/src/lang/object.ts +0 -39
  136. package/src/lang/random.ts +0 -25
  137. package/src/lang/string.ts +0 -95
  138. package/src/lang/time.ts +0 -19
  139. package/src/logging/adapt.ts +0 -49
  140. package/src/logging/formatters.ts +0 -23
  141. package/src/logging/index.ts +0 -106
  142. package/src/md5.ts +0 -318
  143. package/src/url.ts +0 -185
  144. package/src/validators/array.ts +0 -97
  145. package/src/validators/base.ts +0 -145
  146. package/src/validators/boolean.ts +0 -21
  147. package/src/validators/datetime.ts +0 -39
  148. package/src/validators/factory.ts +0 -244
  149. package/src/validators/index.ts +0 -9
  150. package/src/validators/number.ts +0 -54
  151. package/src/validators/object.ts +0 -101
  152. package/src/validators/one-of.ts +0 -33
  153. package/src/validators/string.ts +0 -72
@@ -1,97 +0,0 @@
1
- import { success, failed } from '../lang/index.js'
2
- import {
3
- getValidatorGenerator,
4
- type CommonOptions,
5
- type Validator,
6
- type Validated,
7
- type PrimitiveType,
8
- } from './base.js'
9
-
10
- /** 验证元素数量任意、元素类型相同的数组 */
11
- export interface ArrayOptions extends CommonOptions {
12
- /** 验证数组各元素 */
13
- item: Validator<unknown, CommonOptions>
14
-
15
- /** 数组最小长度 */
16
- min?: number
17
-
18
- /** 数组最大长度 */
19
- max?: number
20
-
21
- /** 是否对数组元素进行去重 @defaults false */
22
- unique?: boolean
23
-
24
- /** 如果传入的不是数组,是否要将其视为数组内元素,包裹成数组 */
25
- toArray?: boolean
26
- }
27
-
28
- type ArrayValues<Options extends ArrayOptions> = Validated<
29
- Options extends { item: Validator<infer T, CommonOptions> } ? T : never,
30
- Options extends { item: Validator<unknown, infer T> } ? T : never
31
- >[]
32
-
33
- export function getArrayValidator<Options extends ArrayOptions>(options: Options) {
34
- return getValidatorGenerator<ArrayValues<Options>, Options>(
35
- function validate(field, value, options) {
36
- if (!Array.isArray(value)) {
37
- if (options.toArray) value = [value as PrimitiveType]
38
- else return failed(`${field} should be an array`)
39
- }
40
-
41
- let formatted = []
42
- if (typeof options.min === 'number' && value.length < options.min)
43
- return failed(`array ${field}'s length should >= ${options.min}`)
44
-
45
- if (typeof options.max === 'number' && value.length > options.max)
46
- return failed(`array ${field}'s length should <= ${options.max}`)
47
-
48
- const itemValidator = options.item
49
- for (let i = 0; i < value.length; i++) {
50
- const itemResult = itemValidator(`${field}[${i}]`, value[i])
51
- if (itemResult.success) formatted.push(itemResult.data)
52
- else return itemResult
53
- }
54
-
55
- if (options.unique === true) formatted = [...new Set(formatted)]
56
-
57
- return success(formatted as ArrayValues<Options>)
58
- },
59
- )(options)
60
- }
61
-
62
- // ---------------------------------------------------
63
-
64
- /** 验证元素数量固定、类型可以不同的数组 */
65
- export interface TupleOptions extends CommonOptions {
66
- /** 验证数组各元素(validator 与元素一一对应) */
67
- tuple: Validator<unknown, CommonOptions>[]
68
- }
69
-
70
- type TupleValues<Options extends TupleOptions> = {
71
- [Key in keyof Options['tuple']]: Options['tuple'][Key] extends Validator<
72
- infer Value,
73
- infer Options
74
- >
75
- ? Validated<Value, Options>
76
- : never
77
- }
78
-
79
- export function getTupleValidator<const Options extends TupleOptions>(options: Options) {
80
- return getValidatorGenerator<TupleValues<Options>, Options>(
81
- function validate(field, value, options) {
82
- if (!Array.isArray(value)) return failed(`${field} should be an array`)
83
- if (value.length > options.tuple.length)
84
- return failed(`${field} should be a tuple with ${options.tuple.length} items`)
85
-
86
- const formatted = []
87
- // 这种情况不能遍历 value,因为它的长度可能小于 opt.tuple
88
- for (let i = 0; i < options.tuple.length; i++) {
89
- const itemValidator = options.tuple[i]!
90
- const itemResult = itemValidator(`${field}[${i}]`, value[i])
91
- if (itemResult.success) formatted.push(itemResult.data)
92
- else return itemResult
93
- }
94
- return success(formatted as TupleValues<Options>)
95
- },
96
- )(options)
97
- }
@@ -1,145 +0,0 @@
1
- import { success, failed, type MaySuccess } from '../lang/index.js'
2
-
3
- /**
4
- * 支持传入进行验证的值类型
5
- */
6
- export type AllowedInputValue = PrimitiveType | null | undefined
7
-
8
- /**
9
- * JavaScript 基础值类型
10
- */
11
- export type PrimitiveType =
12
- | string
13
- | boolean
14
- | number
15
- | PrimitiveType[]
16
- | [...PrimitiveType[]]
17
- | { [key: string]: PrimitiveType }
18
-
19
- /**
20
- * validator 通用参数
21
- */
22
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
- export interface CommonOptions<Value = any> {
24
- /** 是否允许 null 值 @default false */
25
- null?: boolean
26
-
27
- /** 字段是否必须有值(不能是 undefined) @default true */
28
- required?: boolean
29
-
30
- /**
31
- * 默认值,字段无值(或值为 undefined)时生效,值为 null 不会生效。
32
- * 指定后 required 选项将失去作用。
33
- */
34
- defaults?: Value
35
-
36
- custom?: (input: Value) => MaySuccess<Value>
37
-
38
- // 用来保证传入定制过的 Options 时 TypeScript 不会报不匹配的错
39
- // 例如不加这句时, `{ other: boolean } extends CommonOptions` 是会被 TypeScript 判定为不匹配的:
40
- // error TS2559: Type '{ other: boolean }' has no properties in common with type 'CommonOptions<unknown>'
41
- // 此解决办法来自:https://mariusschulz.com/blog/weak-type-detection-in-typescript
42
- [key: string]: unknown
43
- }
44
-
45
- /**
46
- * 补全了的 Options
47
- */
48
- type FullfiledOptions<Options extends Partial<CommonOptions>> = Omit<
49
- Options,
50
- keyof CommonOptions
51
- > & {
52
- null: Options['null'] extends true ? true : false
53
- required: Options['required'] extends false ? false : true
54
- defaults: Options extends { defaults: infer T } ? T : undefined
55
- custom: Options extends { custom: infer T } ? T : undefined
56
- }
57
-
58
- /**
59
- * 验证完成后能得到的值类型
60
- */
61
- export type Validated<Value, InputOptions extends CommonOptions> =
62
- FullfiledOptions<InputOptions> extends { defaults: undefined }
63
- ? FullfiledOptions<InputOptions> extends { required: false; null: false }
64
- ? Value | undefined
65
- : FullfiledOptions<InputOptions> extends { required: false; null: true }
66
- ? Value | undefined | null
67
- : FullfiledOptions<InputOptions> extends { required: true; null: false }
68
- ? Value
69
- : FullfiledOptions<InputOptions> extends { required: true; null: true }
70
- ? Value | null
71
- : Value
72
- : FullfiledOptions<InputOptions> extends {
73
- defaults: infer T
74
- null: false
75
- }
76
- ? Value | T
77
- : FullfiledOptions<InputOptions> extends { defaults: infer T; null: true }
78
- ? Value | T | null
79
- : never
80
-
81
- /**
82
- * 最终生成的 validator 函数类型
83
- */
84
- export interface Validator<Value, InputOptions extends CommonOptions> {
85
- (input: AllowedInputValue): MaySuccess<Validated<Value, InputOptions>>
86
- (field: string, input: AllowedInputValue): MaySuccess<Validated<Value, InputOptions>>
87
- }
88
-
89
- // -----------------------------------
90
-
91
- /**
92
- * 返回支持指定格式的 options、并按照传入的逻辑进行验证的 validator 的生成器。
93
- * 对 CommonOptions 相关内容的验证以自动包含在里面,只需要传入额外的验证逻辑即可。
94
- */
95
- export function getValidatorGenerator<Value, Options extends CommonOptions>(
96
- validate: (
97
- field: string,
98
- input: PrimitiveType | Validated<Value, Options>,
99
- options: Options,
100
- ) => MaySuccess<Value>,
101
- ) {
102
- return function validatorGenerator<const InputOptions extends Options>(
103
- inputOptions: InputOptions,
104
- ): Validator<Value, InputOptions> {
105
- type Return = MaySuccess<Validated<Value, InputOptions>>
106
- function validator(input: AllowedInputValue): Return
107
- function validator(field: string, input: AllowedInputValue): Return
108
- function validator(field: string | AllowedInputValue, input?: AllowedInputValue) {
109
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
110
- const { null: allowNull = false, required = true, defaults, custom } = inputOptions
111
-
112
- if (typeof field !== 'string') {
113
- input = field
114
- field = 'value'
115
- }
116
-
117
- let value: AllowedInputValue | Validated<Value, Options> = input
118
- if (typeof value === 'undefined') {
119
- if (typeof defaults !== 'undefined') {
120
- value = defaults as Validated<Value, Options>
121
- } else if (required) {
122
- return failed(`${field} is required`)
123
- }
124
- }
125
- if (value === null && !allowNull) return failed(`${field} cannot be null`)
126
- if (value === null || value === undefined) return success(value)
127
-
128
- const validated = validate(field, value, inputOptions)
129
- return validated.success && custom ? custom(validated.data) : validated
130
- }
131
- return validator
132
- }
133
- }
134
-
135
- // -----------------------------------
136
-
137
- /**
138
- * 返回只进行基本检查,不带定制的验证逻辑的 validator。
139
- * 同时也是定制 validator 最小化实现的例子。
140
- */
141
- export const getAnyValidator = getValidatorGenerator<unknown, CommonOptions>(
142
- function validate(field, input) {
143
- return success(input)
144
- },
145
- )
@@ -1,21 +0,0 @@
1
- import { success, failed } from '../lang/index.js'
2
- import { getValidatorGenerator, type CommonOptions } from './base.js'
3
-
4
- export type BooleanOptions = CommonOptions<boolean>
5
-
6
- export const getBooleanValidator = getValidatorGenerator<boolean, BooleanOptions>(
7
- function validate(field, input) {
8
- let value: boolean | null = null
9
- if (typeof input === 'boolean') {
10
- value = input
11
- } else if (typeof input === 'string') {
12
- const str = input.trim().toLowerCase()
13
- if (['1', 'true', 'on', 'yes'].includes(str)) value = true
14
- else if (['0', 'false', 'off', 'no'].includes(str)) value = false
15
- } else if (typeof input === 'number') {
16
- if (input === 1) value = true
17
- else if (input === 0) value = false
18
- }
19
- return value === null ? failed(`${field} must be true or false`) : success(value)
20
- },
21
- )
@@ -1,39 +0,0 @@
1
- /**
2
- * 验证日期时间类型的值,依赖 dayjs
3
- */
4
- import dayjs, { Dayjs } from 'dayjs'
5
- import { success, failed } from '../lang/index.js'
6
- import { getValidatorGenerator, type CommonOptions } from './base.js'
7
-
8
- export interface DatetimeOptions extends CommonOptions<number> {
9
- raw?: boolean // 为 true 则返回原生 Date 对象;否则返回 Dayjs 对象(默认)
10
- }
11
-
12
- export type DatetimeValue<Options extends DatetimeOptions> = Options extends {
13
- raw: true
14
- }
15
- ? Date
16
- : Dayjs
17
-
18
- export function getDatetimeValidator<const Options extends DatetimeOptions>(
19
- options: Options = {} as Options
20
- ) {
21
- return getValidatorGenerator<DatetimeValue<Options>, Options>(function validate(field, value) {
22
- let dayjsValue: Dayjs
23
-
24
- if (typeof value === 'number') {
25
- dayjsValue = dayjs.unix(value)
26
- if (!dayjsValue.isValid()) return failed(`${field} must be a valid unix timestamp`)
27
- } else if (typeof value === 'string') {
28
- dayjsValue = dayjs(value)
29
- if (!dayjsValue.isValid()) return failed(`${field} must be a valid datetime string`)
30
- } else if (value instanceof Date || value instanceof Dayjs) {
31
- dayjsValue = dayjs(value)
32
- if (!dayjsValue.isValid()) return failed(`${field} must be a valid Date or Dayjs object`)
33
- } else {
34
- return failed(`${field} must be a datetime string or unix timestamp`)
35
- }
36
-
37
- return success((options.raw ? dayjsValue.toDate() : dayjsValue) as DatetimeValue<Options>)
38
- })(options)
39
- }
@@ -1,244 +0,0 @@
1
- /**
2
- * 实现创建 validator 的快捷方式
3
- */
4
- import {
5
- type ArrayOptions,
6
- getArrayValidator,
7
- type TupleOptions,
8
- getTupleValidator,
9
- } from './array.js'
10
- import { type Validator, type CommonOptions, type Validated, getAnyValidator } from './base.js'
11
- import { type BooleanOptions, getBooleanValidator } from './boolean.js'
12
- import { type DatetimeOptions, type DatetimeValue, getDatetimeValidator } from './datetime.js'
13
- import { type NumberOptions, type NumberValueWithChoices, getNumberValidator } from './number.js'
14
- import {
15
- type RecordOptions,
16
- getRecordValidator,
17
- type StructOptions,
18
- getStructValidator,
19
- } from './object.js'
20
- import { type OneOfOptions, getOneOfValidator } from './one-of.js'
21
- import { type StringOptions, type StringValueWithChoices, getStringValidator } from './string.js'
22
-
23
- export interface AnyDefinition extends CommonOptions {
24
- type: 'any'
25
- }
26
- export interface BooleanDefinition extends BooleanOptions {
27
- type: 'boolean'
28
- }
29
- export interface NumberDefinition extends NumberOptions {
30
- type: 'number'
31
- }
32
- export interface StringDefinition extends StringOptions {
33
- type: 'string'
34
- }
35
- export interface DatetimeDefinition extends DatetimeOptions {
36
- type: 'datetime'
37
- }
38
- export interface ArrayDefinition extends Omit<ArrayOptions, 'item'> {
39
- type: 'array'
40
- item: Definition
41
- }
42
- export interface TupleDefinition extends Omit<TupleOptions, 'tuple'> {
43
- type: 'tuple'
44
- tuple: Definition[]
45
- }
46
- export interface StructDefinition extends Omit<StructOptions, 'struct'> {
47
- type: 'struct'
48
- struct: Record<string, Definition>
49
- }
50
- export interface RecordDefinition extends Omit<RecordOptions, 'record'> {
51
- type: 'record'
52
- record: Definition
53
- }
54
- export interface OneOfDefinition extends Omit<OneOfOptions, 'validators'> {
55
- type: 'oneOf'
56
- validators: Definition[]
57
- }
58
-
59
- export type Definition =
60
- | AnyDefinition
61
- | BooleanDefinition
62
- | NumberDefinition
63
- | StringDefinition
64
- | DatetimeDefinition
65
- | ArrayDefinition
66
- | TupleDefinition
67
- | StructDefinition
68
- | RecordDefinition
69
- | OneOfDefinition
70
-
71
- export type ValueOfDefinition<Def extends Definition> = Def extends AnyDefinition
72
- ? unknown
73
- : Def extends BooleanDefinition
74
- ? boolean
75
- : Def extends NumberDefinition
76
- ? NumberValueWithChoices<Def>
77
- : Def extends StringDefinition
78
- ? StringValueWithChoices<Def>
79
- : Def extends DatetimeDefinition
80
- ? DatetimeValue<Def>
81
- : Def extends ArrayDefinition
82
- ? Validated<ValueOfDefinition<Def['item']>, Def['item']>[]
83
- : Def extends TupleDefinition
84
- ? {
85
- [Key in keyof Def['tuple']]: Def['tuple'][Key] extends Definition
86
- ? Validated<ValueOfDefinition<Def['tuple'][Key]>, Def['tuple'][Key]>
87
- : Def['tuple'][Key]
88
- }
89
- : Def extends StructDefinition
90
- ? {
91
- [Key in keyof Def['struct']]: Validated<
92
- ValueOfDefinition<Def['struct'][Key]>,
93
- Def['struct'][Key]
94
- >
95
- }
96
- : Def extends RecordDefinition
97
- ? Record<string, Validated<ValueOfDefinition<Def['record']>, Def['record']>>
98
- : Def extends OneOfDefinition
99
- ? {
100
- [Key in keyof Def['validators']]: Def['validators'][Key] extends Definition
101
- ? Validated<ValueOfDefinition<Def['validators'][Key]>, Def['validators'][Key]>
102
- : Def['validators'][Key]
103
- }[number]
104
- : never
105
-
106
- export type OptionsFromDefinition<Def extends Definition> = Def extends ArrayDefinition
107
- ? Omit<Def, 'item'> & { item: ValidatorForDefinition<Def['item']> }
108
- : Def extends TupleDefinition
109
- ? Omit<Def, 'tuple'> & {
110
- tuple: {
111
- [Key in keyof Def['tuple']]: Def['tuple'][Key] extends Definition
112
- ? ValidatorForDefinition<Def['tuple'][Key]>
113
- : never
114
- }
115
- }
116
- : Def extends StructDefinition
117
- ? Omit<Def, 'struct'> & {
118
- struct: { [Key in keyof Def['struct']]: ValidatorForDefinition<Def['struct'][Key]> }
119
- }
120
- : Def extends RecordDefinition
121
- ? Omit<Def, 'record'> & { record: ValidatorForDefinition<Def['record']> }
122
- : Def
123
-
124
- export type ValidatorForDefinition<Def extends Definition> = Validator<
125
- ValueOfDefinition<Def>,
126
- OptionsFromDefinition<Def>
127
- >
128
-
129
- export type ResultForDefinition<Def extends Definition> = ReturnType<ValidatorForDefinition<Def>>
130
-
131
- export function getValidator<const InputDefinition extends Definition>(
132
- definition: InputDefinition
133
- ): ValidatorForDefinition<InputDefinition> {
134
- type GotValidator = ValidatorForDefinition<InputDefinition>
135
- switch (definition.type) {
136
- case 'any':
137
- return getAnyValidator(definition) as GotValidator
138
- case 'boolean':
139
- return getBooleanValidator(definition) as GotValidator
140
- case 'number':
141
- return getNumberValidator(definition) as GotValidator
142
- case 'string':
143
- return getStringValidator(definition) as GotValidator
144
- case 'datetime':
145
- return getDatetimeValidator(definition) as GotValidator
146
- case 'array':
147
- // @ts-ignore 允许递归类型推断
148
- return getArrayValidator({
149
- // @ts-ignore 允许递归类型推断
150
- ...definition,
151
- item: getValidator(definition.item),
152
- }) as GotValidator
153
- case 'tuple':
154
- return getTupleValidator({
155
- ...definition,
156
- tuple: definition.tuple.map(def => getValidator(def)),
157
- }) as GotValidator
158
- case 'struct': {
159
- const struct: Record<string, Validator<unknown, CommonOptions>> = {}
160
- for (const [key, def] of Object.entries(definition.struct)) struct[key] = getValidator(def)
161
- return getStructValidator({ ...definition, struct }) as GotValidator
162
- }
163
- case 'record':
164
- return getRecordValidator({
165
- ...definition,
166
- record: getValidator(definition.record),
167
- }) as GotValidator
168
- case 'oneOf':
169
- return getOneOfValidator({
170
- ...definition,
171
- validators: definition.validators.map(def => getValidator(def)),
172
- }) as GotValidator
173
- }
174
- }
175
-
176
- // ---------------- 测试用例 -----------------
177
-
178
- // const v1 = getValidator({ type: 'string' })(1)
179
- // const v2 = getValidator({ type: 'string', null: true })(1)
180
- // const v3 = getValidator({ type: 'string', null: true, required: false })(1)
181
- // const v4 = getValidator({ type: 'string', null: true, required: false, choices: ['a', 'b', 'c'] })(
182
- // 1,
183
- // )
184
- // const v5 = getValidator({
185
- // type: 'string',
186
- // null: true,
187
- // required: false,
188
- // choices: ['a', 'b', 'c'],
189
- // defaults: 'd',
190
- // })(1)
191
- // const v6 = getValidator({
192
- // type: 'array',
193
- // null: true,
194
- // required: false,
195
- // item: { type: 'string', null: true, choices: ['a', 'b', 'c'] },
196
- // })(1)
197
- // const v7 = getValidator({
198
- // type: 'tuple',
199
- // tuple: [
200
- // { type: 'string', choices: ['a', 'b', 'c'] },
201
- // { type: 'string', null: true },
202
- // ],
203
- // })(1)
204
- // if (v7.success) {
205
- // const [a, b] = v7.data
206
- // }
207
- // const v8 = getValidator({
208
- // type: 'struct',
209
- // struct: {
210
- // x: { type: 'string', choices: ['a', 'b', 'c'] },
211
- // y: { type: 'string', null: true },
212
- // },
213
- // })(1)
214
- // if (v8.success) {
215
- // const { x, y } = v8.data
216
- // }
217
- // const v9 = getValidator({
218
- // type: 'record',
219
- // record: { type: 'string', null: true, choices: ['a', 'b', 'c'] },
220
- // })(1)
221
- // const v10 = getValidator({
222
- // type: 'oneOf',
223
- // validators: [
224
- // { type: 'string', choices: ['a', 'b', 'c'] },
225
- // { type: 'number', null: true },
226
- // ],
227
- // defaults: true,
228
- // })(1)
229
- // const v11 = getValidator({
230
- // type: 'string',
231
- // custom(value) {
232
- // return { success: true, data: value }
233
- // },
234
- // defaults: 'some text',
235
- // })(1)
236
- // const v12 = getValidator({
237
- // type: 'datetime',
238
- // null: true,
239
- // required: false,
240
- // })(1)
241
- // const v13 = getValidator({
242
- // type: 'datetime',
243
- // raw: true,
244
- // })(1)
@@ -1,9 +0,0 @@
1
- export * from './base.js'
2
- export * from './boolean.js'
3
- export * from './number.js'
4
- export * from './string.js'
5
- export * from './datetime.js'
6
- export * from './array.js'
7
- export * from './object.js'
8
- export * from './one-of.js'
9
- export * from './factory.js'
@@ -1,54 +0,0 @@
1
- import { truthy, success, failed } from '../lang/index.js'
2
- import { getValidatorGenerator, type CommonOptions } from './base.js'
3
-
4
- export interface NumberOptions extends CommonOptions<number> {
5
- /** 数值最小值 */
6
- min?: number
7
-
8
- /** 数值最大值 */
9
- max?: number
10
-
11
- /** 是否允许小数 @default false */
12
- float?: boolean
13
-
14
- /**
15
- * 指定可选值
16
- * 若指定,前几个选项将不再生效 */
17
- choices?: number[] | Record<number, string>
18
- }
19
-
20
- export type NumberValueWithChoices<Options extends NumberOptions> = Options extends {
21
- choices: (infer T)[]
22
- }
23
- ? T
24
- : Options extends { choices: Record<number, string> }
25
- ? Options['choices'][keyof Options['choices']]
26
- : number
27
-
28
- export function getNumberValidator<const Options extends NumberOptions>(
29
- options: Options = {} as Options,
30
- ) {
31
- return getValidatorGenerator<NumberValueWithChoices<Options>, Options>(
32
- function validate(field, value) {
33
- if (typeof value === 'string') value = parseFloat(value)
34
- if (typeof value !== 'number' || !isFinite(value))
35
- return failed(`${field} must be a valid number`)
36
-
37
- if ('choices' in options && options.choices) {
38
- const choices = Array.isArray(options.choices)
39
- ? options.choices
40
- : Object.values(options.choices).map(v => parseInt(v, 10))
41
- if (!choices.includes(value))
42
- return failed(`${field} can only be one of ${choices.join(', ')}.`)
43
- } else {
44
- if (!truthy(options.float) && value % 1 !== 0) return failed(`${field} must be a integer`)
45
- if (typeof options.min === 'number' && value < options.min)
46
- return failed(`${field} must >= ${options.min}`)
47
- if (typeof options.max === 'number' && value > options.max)
48
- return failed(`${field} must <= ${options.max}`)
49
- }
50
-
51
- return success(value as NumberValueWithChoices<Options>)
52
- },
53
- )(options)
54
- }