@wwog/react 1.3.12 → 1.3.13

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.
@@ -1,51 +1,49 @@
1
1
  // ==== 基础规则类型 ====
2
2
  export type BaseRule<TAll, TValue> = {
3
- required?: boolean;
4
- message?: string;
5
- validator?: (value: TValue, data: Partial<TAll>) => boolean | string;
6
- dependsOn?: (data: Partial<TAll>) => boolean | string; // 支持依赖校验
7
- };
3
+ required?: boolean
4
+ message?: string
5
+ validator?: (value: TValue, data: Partial<TAll>) => boolean | string
6
+ dependsOn?: (data: Partial<TAll>) => boolean | string // 支持依赖校验
7
+ }
8
8
 
9
9
  // ==== 长度相关规则(字符串和数组共用) ====
10
10
  export type LengthRuleProps = {
11
- min?: number;
12
- max?: number;
13
- len?: number;
14
- };
11
+ min?: number
12
+ max?: number
13
+ len?: number
14
+ }
15
15
 
16
16
  // ==== 数字范围规则 ====
17
17
  export type NumberRangeProps = {
18
- min?: number;
19
- max?: number;
20
- };
18
+ min?: number
19
+ max?: number
20
+ }
21
21
 
22
22
  // ==== 字符串特有规则 ====
23
23
  export type StringSpecificProps = {
24
- regex?: RegExp;
25
- email?: boolean;
26
- url?: boolean;
27
- phone?: boolean;
28
- };
24
+ regex?: RegExp
25
+ email?: boolean
26
+ url?: boolean
27
+ phone?: boolean
28
+ }
29
29
 
30
30
  // ==== 数组特有规则 ====
31
31
  export type ArraySpecificProps = {
32
- unique?: boolean;
33
- };
32
+ unique?: boolean
33
+ }
34
34
 
35
35
  // ==== 各类型规则 ====
36
- export type NumberRule<TAll> = BaseRule<TAll, number> & NumberRangeProps;
36
+ export type NumberRule<TAll> = BaseRule<TAll, number> & NumberRangeProps
37
37
 
38
- export type StringRule<TAll> = BaseRule<TAll, string> &
39
- LengthRuleProps &
40
- StringSpecificProps;
38
+ export type StringRule<TAll> = BaseRule<TAll, string> & LengthRuleProps & StringSpecificProps
41
39
 
42
- export type BooleanRule<TAll> = BaseRule<TAll, boolean>;
40
+ export type BooleanRule<TAll> = BaseRule<TAll, boolean>
43
41
 
44
42
  export type ArrayRule<TAll, U> = BaseRule<TAll, U[]> &
45
43
  LengthRuleProps &
46
44
  ArraySpecificProps & {
47
- elementRule?: FieldRule<U, TAll>; // 元素级规则
48
- };
45
+ elementRule?: FieldRule<U, TAll> // 元素级规则
46
+ }
49
47
 
50
48
  // ==== 泛型推导:字段类型 → 规则类型 ====
51
49
  export type FieldRule<TValue, TAll> = TValue extends string
@@ -56,49 +54,46 @@ export type FieldRule<TValue, TAll> = TValue extends string
56
54
  ? BooleanRule<TAll>
57
55
  : TValue extends (infer U)[]
58
56
  ? ArrayRule<TAll, U>
59
- : BaseRule<TAll, TValue>;
57
+ : BaseRule<TAll, TValue>
60
58
 
61
59
  // ==== 描述对象 ====
62
60
  export type RuleDescription<T extends Record<string, unknown>> = {
63
- [K in keyof T]?: FieldRule<T[K], T> | FieldRule<T[K], T>[];
64
- };
61
+ [K in keyof T]?: FieldRule<T[K], T> | FieldRule<T[K], T>[]
62
+ }
65
63
 
66
64
  // ==== Required 判断 ====
67
- type IsRequired<R> = R extends { required: true } ? true : false;
65
+ type IsRequired<R> = R extends {required: true} ? true : false
68
66
 
69
- export type ApplyRules<
70
- T extends Record<string, unknown>,
71
- R extends RuleDescription<T>,
72
- > = {
73
- [K in keyof T]: IsRequired<R[K]> extends true ? T[K] : T[K] | undefined;
74
- };
67
+ export type ApplyRules<T extends Record<string, unknown>, R extends RuleDescription<T>> = {
68
+ [K in keyof T]: IsRequired<R[K]> extends true ? T[K] : T[K] | undefined
69
+ }
75
70
 
76
71
  // ==== 错误收集 ====
77
- type FieldErrors<T> = Partial<Record<keyof T, string[]>>;
72
+ type FieldErrors<T> = Partial<Record<keyof T, string[]>>
78
73
 
79
74
  function pushError<T extends Record<string, unknown>>(
80
75
  fieldErrors: FieldErrors<T>,
81
76
  field: keyof T,
82
- msg: string
77
+ msg: string,
83
78
  ) {
84
- if (!msg) return;
85
- if (!fieldErrors[field]) fieldErrors[field] = [];
86
- (fieldErrors[field] as string[]).push(msg);
79
+ if (!msg) return
80
+ if (!fieldErrors[field]) fieldErrors[field] = []
81
+ ;(fieldErrors[field] as string[]).push(msg)
87
82
  }
88
83
 
89
84
  function isPresent(value: unknown): boolean {
90
- if (value === null || value === undefined) return false;
91
- if (typeof value === 'string') return value.trim().length > 0;
92
- if (Array.isArray(value)) return value.length > 0;
93
- return true;
85
+ if (value === null || value === undefined) return false
86
+ if (typeof value === 'string') return value.trim().length > 0
87
+ if (Array.isArray(value)) return value.length > 0
88
+ return true
94
89
  }
95
90
 
96
91
  function isValueProvided(value: unknown): boolean {
97
- return value !== null && value !== undefined;
92
+ return value !== null && value !== undefined
98
93
  }
99
94
 
100
95
  function defaultMsg(field: string | number | symbol, reason: string) {
101
- return `${String(field)} ${reason}`;
96
+ return `${String(field)} ${reason}`
102
97
  }
103
98
 
104
99
  // ==== 内置校验器 ====
@@ -106,7 +101,7 @@ const builtins = {
106
101
  email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
107
102
  url: /^(https?:\/\/)?([\w.-]+)\.([a-z]{2,6})([/\w .-]*)*\/?$/,
108
103
  phone: /^1[3-9]\d{9}$/, // 中国手机号
109
- };
104
+ }
110
105
 
111
106
  // ==== 单字段校验 ====
112
107
  function validateRule<T extends Record<string, unknown>, V>(
@@ -114,227 +109,149 @@ function validateRule<T extends Record<string, unknown>, V>(
114
109
  value: V,
115
110
  rule: FieldRule<V, T>,
116
111
  data: Partial<T>,
117
- fieldErrors: FieldErrors<T>
112
+ fieldErrors: FieldErrors<T>,
118
113
  ) {
119
- const present = isPresent(value);
120
- const valueProvided = isValueProvided(value);
114
+ const present = isPresent(value)
115
+ const valueProvided = isValueProvided(value)
121
116
 
122
117
  // required
123
118
  if (rule.required && !present) {
124
- pushError(fieldErrors, key, rule.message ?? defaultMsg(key, '为必填项'));
125
- return;
119
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, '为必填项'))
120
+ return
126
121
  }
127
122
  // 如果值没有提供且不是必填,跳过验证
128
- if (!valueProvided && !rule.required) return;
123
+ if (!valueProvided && !rule.required) return
129
124
 
130
125
  // dependsOn
131
126
  if (rule.dependsOn) {
132
- const res = rule.dependsOn(data);
127
+ const res = rule.dependsOn(data)
133
128
  if (res === false)
134
- pushError(
135
- fieldErrors,
136
- key,
137
- rule.message ?? defaultMsg(key, '依赖条件未满足')
138
- );
139
- else if (typeof res === 'string') pushError(fieldErrors, key, res);
129
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, '依赖条件未满足'))
130
+ else if (typeof res === 'string') pushError(fieldErrors, key, res)
140
131
  }
141
132
 
142
133
  // string 相关校验
143
134
  if (typeof value === 'string') {
144
- const stringRule = rule as StringRule<T>;
145
- const { len, min, max, regex, email, url, phone } = stringRule;
135
+ const stringRule = rule as StringRule<T>
136
+ const {len, min, max, regex, email, url, phone} = stringRule
146
137
 
147
138
  if (typeof len === 'number' && value.length !== len) {
148
- pushError(
149
- fieldErrors,
150
- key,
151
- rule.message ?? defaultMsg(key, `长度必须为 ${len}`)
152
- );
139
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, `长度必须为 ${len}`))
153
140
  }
154
141
  if (typeof min === 'number' && value.length < min) {
155
- pushError(
156
- fieldErrors,
157
- key,
158
- rule.message ?? defaultMsg(key, `长度不能少于 ${min}`)
159
- );
142
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, `长度不能少于 ${min}`))
160
143
  }
161
144
  if (typeof max === 'number' && value.length > max) {
162
- pushError(
163
- fieldErrors,
164
- key,
165
- rule.message ?? defaultMsg(key, `长度不能超过 ${max}`)
166
- );
145
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, `长度不能超过 ${max}`))
167
146
  }
168
147
  if (regex && !regex.test(value)) {
169
- pushError(
170
- fieldErrors,
171
- key,
172
- rule.message ?? defaultMsg(key, '格式不正确')
173
- );
148
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, '格式不正确'))
174
149
  }
175
150
  if (email && !builtins.email.test(value)) {
176
- pushError(
177
- fieldErrors,
178
- key,
179
- rule.message ?? defaultMsg(key, '不是有效的邮箱')
180
- );
151
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, '不是有效的邮箱'))
181
152
  }
182
153
  if (url && !builtins.url.test(value)) {
183
- pushError(
184
- fieldErrors,
185
- key,
186
- rule.message ?? defaultMsg(key, '不是有效的URL')
187
- );
154
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, '不是有效的URL'))
188
155
  }
189
156
  if (phone && !builtins.phone.test(value)) {
190
- pushError(
191
- fieldErrors,
192
- key,
193
- rule.message ?? defaultMsg(key, '不是有效的手机号')
194
- );
157
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, '不是有效的手机号'))
195
158
  }
196
159
  }
197
160
 
198
161
  // number 相关校验
199
162
  if (typeof value === 'number') {
200
- const numberRule = rule as NumberRule<T>;
201
- const { min, max } = numberRule;
163
+ const numberRule = rule as NumberRule<T>
164
+ const {min, max} = numberRule
202
165
  if (typeof min === 'number' && value < min) {
203
- pushError(
204
- fieldErrors,
205
- key,
206
- rule.message ?? defaultMsg(key, `不能小于 ${min}`)
207
- );
166
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, `不能小于 ${min}`))
208
167
  }
209
168
  if (typeof max === 'number' && value > max) {
210
- pushError(
211
- fieldErrors,
212
- key,
213
- rule.message ?? defaultMsg(key, `不能大于 ${max}`)
214
- );
169
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, `不能大于 ${max}`))
215
170
  }
216
171
  }
217
172
 
218
173
  // array 相关校验
219
174
  if (Array.isArray(value)) {
220
- const arrayRule = rule as ArrayRule<T, unknown>;
221
- const { len, min, max, unique, elementRule } = arrayRule;
175
+ const arrayRule = rule as ArrayRule<T, unknown>
176
+ const {len, min, max, unique, elementRule} = arrayRule
222
177
 
223
178
  if (typeof len === 'number' && value.length !== len) {
224
- pushError(
225
- fieldErrors,
226
- key,
227
- rule.message ?? defaultMsg(key, `长度必须为 ${len}`)
228
- );
179
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, `长度必须为 ${len}`))
229
180
  }
230
181
  if (typeof min === 'number' && value.length < min) {
231
- pushError(
232
- fieldErrors,
233
- key,
234
- rule.message ?? defaultMsg(key, `长度不能小于 ${min}`)
235
- );
182
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, `长度不能小于 ${min}`))
236
183
  }
237
184
  if (typeof max === 'number' && value.length > max) {
238
- pushError(
239
- fieldErrors,
240
- key,
241
- rule.message ?? defaultMsg(key, `长度不能大于 ${max}`)
242
- );
185
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, `长度不能大于 ${max}`))
243
186
  }
244
187
  if (unique && new Set(value).size !== value.length) {
245
- pushError(
246
- fieldErrors,
247
- key,
248
- rule.message ?? defaultMsg(key, '元素必须唯一')
249
- );
188
+ pushError(fieldErrors, key, rule.message ?? defaultMsg(key, '元素必须唯一'))
250
189
  }
251
190
  if (elementRule) {
252
- (value as unknown[]).forEach((v, i) => {
191
+ ;(value as unknown[]).forEach((v, i) => {
253
192
  validateRule(
254
193
  `${String(key)}[${i}]` as keyof T,
255
194
  v as unknown,
256
195
  elementRule as FieldRule<unknown, T>,
257
196
  data,
258
- fieldErrors
259
- );
260
- });
197
+ fieldErrors,
198
+ )
199
+ })
261
200
  }
262
201
  }
263
202
 
264
203
  // 自定义 validator
265
204
  if (rule.validator) {
266
205
  const res = (
267
- rule.validator as
268
- | ((value: unknown, data: Partial<T>) => boolean | string)
269
- | undefined
270
- )?.(value as unknown, data);
271
- if (res === false)
272
- pushError(
273
- fieldErrors,
274
- key,
275
- rule.message ?? defaultMsg(key, '校验未通过')
276
- );
277
- else if (typeof res === 'string') pushError(fieldErrors, key, res);
206
+ rule.validator as ((value: unknown, data: Partial<T>) => boolean | string) | undefined
207
+ )?.(value as unknown, data)
208
+ if (res === false) pushError(fieldErrors, key, rule.message ?? defaultMsg(key, '校验未通过'))
209
+ else if (typeof res === 'string') pushError(fieldErrors, key, res)
278
210
  }
279
211
  }
280
212
 
281
213
  // ==== 主函数 ====
282
- export function ruleChecker<
283
- T extends Record<string, unknown>,
284
- R extends RuleDescription<T>,
285
- >(
214
+ export function ruleChecker<T extends Record<string, unknown>, R extends RuleDescription<T>>(
286
215
  data: Partial<T>,
287
- rules: R
216
+ rules: R,
288
217
  ):
289
- | { valid: true; data: ApplyRules<T, R> }
290
- | { valid: false; errors: string[]; fieldErrors: FieldErrors<T> } {
291
- const fieldErrors: FieldErrors<T> = {};
218
+ | {valid: true; data: ApplyRules<T, R>}
219
+ | {valid: false; errors: string[]; fieldErrors: FieldErrors<T>} {
220
+ const fieldErrors: FieldErrors<T> = {}
292
221
 
293
222
  for (const k in rules) {
294
- const key = k as keyof T;
223
+ const key = k as keyof T
295
224
  const ruleOrRules = rules[key] as
296
225
  | FieldRule<T[typeof key] | undefined, T>
297
226
  | FieldRule<T[typeof key] | undefined, T>[]
298
- | undefined;
299
- if (!ruleOrRules) continue;
227
+ | undefined
228
+ if (!ruleOrRules) continue
300
229
 
301
- const value = data[key] as T[typeof key] | undefined;
230
+ const value = data[key] as T[typeof key] | undefined
302
231
 
303
232
  // 支持单个规则或规则数组
304
233
  if (Array.isArray(ruleOrRules)) {
305
234
  // 处理规则数组
306
235
  for (const rule of ruleOrRules) {
307
- validateRule<T, T[typeof key] | undefined>(
308
- key,
309
- value,
310
- rule,
311
- data,
312
- fieldErrors
313
- );
236
+ validateRule<T, T[typeof key] | undefined>(key, value, rule, data, fieldErrors)
314
237
  }
315
238
  } else {
316
239
  // 处理单个规则
317
- validateRule<T, T[typeof key] | undefined>(
318
- key,
319
- value,
320
- ruleOrRules,
321
- data,
322
- fieldErrors
323
- );
240
+ validateRule<T, T[typeof key] | undefined>(key, value, ruleOrRules, data, fieldErrors)
324
241
  }
325
242
  }
326
243
 
327
244
  // 聚合错误时,避免 [] 被推断为 never[] 导致的类型问题
328
- const errors: string[] = (
329
- Object.values(fieldErrors) as Array<string[] | undefined>
330
- ).reduce<string[]>((acc, v) => {
331
- if (v) acc.push(...v);
332
- return acc;
333
- }, []);
245
+ const errors: string[] = (Object.values(fieldErrors) as Array<string[] | undefined>).reduce<
246
+ string[]
247
+ >((acc, v) => {
248
+ if (v) acc.push(...v)
249
+ return acc
250
+ }, [])
334
251
 
335
252
  if (errors.length > 0) {
336
- return { valid: false, errors, fieldErrors };
253
+ return {valid: false, errors, fieldErrors}
337
254
  }
338
255
 
339
- return { valid: true, data: data as ApplyRules<T, R> };
256
+ return {valid: true, data: data as ApplyRules<T, R>}
340
257
  }
@@ -28,104 +28,103 @@
28
28
  * a | am | pm
29
29
  */
30
30
  export function formatDate(schema: string, date?: Date): string {
31
- const d = date || new Date();
32
- const year = d.getFullYear();
33
- const month = d.getMonth() + 1;
34
- const day = d.getDate();
35
- const hour = d.getHours();
36
- const minute = d.getMinutes();
37
- const second = d.getSeconds();
38
- const millisecond = d.getMilliseconds();
39
- const week = d.getDay();
40
- const weekName = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
31
+ const d = date || new Date()
32
+ const year = d.getFullYear()
33
+ const month = d.getMonth() + 1
34
+ const day = d.getDate()
35
+ const hour = d.getHours()
36
+ const minute = d.getMinutes()
37
+ const second = d.getSeconds()
38
+ const millisecond = d.getMilliseconds()
39
+ const week = d.getDay()
40
+ const weekName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
41
41
  const weekFullName = [
42
- "Sunday",
43
- "Monday",
44
- "Tuesday",
45
- "Wednesday",
46
- "Thursday",
47
- "Friday",
48
- "Saturday",
49
- ];
42
+ 'Sunday',
43
+ 'Monday',
44
+ 'Tuesday',
45
+ 'Wednesday',
46
+ 'Thursday',
47
+ 'Friday',
48
+ 'Saturday',
49
+ ]
50
50
  const monthName = [
51
- "Jan",
52
- "Feb",
53
- "Mar",
54
- "Apr",
55
- "May",
56
- "Jun",
57
- "Jul",
58
- "Aug",
59
- "Sep",
60
- "Oct",
61
- "Nov",
62
- "Dec",
63
- ];
51
+ 'Jan',
52
+ 'Feb',
53
+ 'Mar',
54
+ 'Apr',
55
+ 'May',
56
+ 'Jun',
57
+ 'Jul',
58
+ 'Aug',
59
+ 'Sep',
60
+ 'Oct',
61
+ 'Nov',
62
+ 'Dec',
63
+ ]
64
64
  const monthFullName = [
65
- "January",
66
- "February",
67
- "March",
68
- "April",
69
- "May",
70
- "June",
71
- "July",
72
- "August",
73
- "September",
74
- "October",
75
- "November",
76
- "December",
77
- ];
65
+ 'January',
66
+ 'February',
67
+ 'March',
68
+ 'April',
69
+ 'May',
70
+ 'June',
71
+ 'July',
72
+ 'August',
73
+ 'September',
74
+ 'October',
75
+ 'November',
76
+ 'December',
77
+ ]
78
78
  // 直接使用 week 索引,不进行转换,因为 getDay() 已经返回了正确的星期索引 (0-6)
79
- const weekFull = weekFullName[week]!;
80
- const weekShort = weekName[week]!;
81
- const monthIndex = month - 1;
82
- const monthFull = monthFullName[monthIndex]!;
83
- const monthShort = monthName[monthIndex]!;
79
+ const weekFull = weekFullName[week]!
80
+ const weekShort = weekName[week]!
81
+ const monthIndex = month - 1
82
+ const monthFull = monthFullName[monthIndex]!
83
+ const monthShort = monthName[monthIndex]!
84
84
  const map: Record<string, string> = {
85
85
  YY: year.toString().slice(2),
86
86
  YYYY: year.toString(),
87
87
  M: month.toString(),
88
- MM: month.toString().padStart(2, "0"),
88
+ MM: month.toString().padStart(2, '0'),
89
89
  MMM: monthShort,
90
90
  MMMM: monthFull,
91
91
  D: day.toString(),
92
- DD: day.toString().padStart(2, "0"),
92
+ DD: day.toString().padStart(2, '0'),
93
93
  d: week.toString(),
94
94
  dd: weekShort,
95
95
  ddd: weekShort,
96
96
  dddd: weekFull,
97
97
  H: hour.toString(),
98
- HH: hour.toString().padStart(2, "0"),
98
+ HH: hour.toString().padStart(2, '0'),
99
99
  h: (hour % 12).toString(),
100
- hh: (hour % 12).toString().padStart(2, "0"),
100
+ hh: (hour % 12).toString().padStart(2, '0'),
101
101
  m: minute.toString(),
102
- mm: minute.toString().padStart(2, "0"),
102
+ mm: minute.toString().padStart(2, '0'),
103
103
  s: second.toString(),
104
- ss: second.toString().padStart(2, "0"),
105
- SSS: millisecond.toString().padStart(3, "0"),
106
- Z: "+08:00",
107
- ZZ: "+0800",
108
- A: hour < 12 ? "AM" : "PM",
109
- a: hour < 12 ? "am" : "pm",
110
- };
104
+ ss: second.toString().padStart(2, '0'),
105
+ SSS: millisecond.toString().padStart(3, '0'),
106
+ Z: '+08:00',
107
+ ZZ: '+0800',
108
+ A: hour < 12 ? 'AM' : 'PM',
109
+ a: hour < 12 ? 'am' : 'pm',
110
+ }
111
111
 
112
112
  return schema.replace(
113
113
  /YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|SSS|Z{1,2}|A|a/g,
114
114
  (match) => {
115
- return map[match]!;
116
- }
117
- );
115
+ return map[match]!
116
+ },
117
+ )
118
118
  }
119
119
 
120
120
  export class Counter {
121
- count = 0;
121
+ count = 0
122
122
 
123
123
  /**
124
124
  * @description 获取下一个计数值,不考虑越界。
125
125
  * @description_en Get the next count value, without considering overflow.
126
126
  */
127
127
  next() {
128
- return this.count++;
128
+ return this.count++
129
129
  }
130
130
  }
131
-