@veltra/utils 1.1.35 → 1.2.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/dist/index.d.ts CHANGED
@@ -6,8 +6,6 @@ import { getHighlightChunks } from "./dom/highlight.js";
6
6
  import { getNearestScrollParent, getScrollParents, scrollIntoContainerView } from "./dom/position.js";
7
7
  import { removeStyles, setStyles, withUnit } from "./dom/style.js";
8
8
  import { zIndex } from "./dom/z-index.js";
9
- import { Data, PresetRule, ValidateRule, ValidatorConfig } from "./types/utils/form/validate.js";
10
- import { Validator } from "./form/validate.js";
11
9
  import { createIncrease } from "./helper/create-increase.js";
12
10
  import { createToggle } from "./helper/create-toggle.js";
13
11
  import { AnimeConfig, Tween, TweenConfig } from "./helper/tween.js";
@@ -16,5 +14,5 @@ import { extractNormalVNodes, isComment, isFragment, isTemplate, isTextNode, sha
16
14
  import { middleProxy } from "./reactive/proxy.js";
17
15
  import { DeconstructValue, DefineEvent, Index, Null, RenderReturn, Undef } from "./types/helper.js";
18
16
  import { BreakpointName, ColorType, ComponentProps, ComponentSize, FormComponentProps, PropsWithServerQuery } from "./types/component-common.js";
19
- import { FormContextModel, FormContextProps, injectFormContext, provideFormContext } from "./types/form-context.js";
20
- export { AnimeConfig, BEM, BEMFactory, BreakpointName, CLS_PREFIX, ColorType, ComponentProps, ComponentSize, Data, DeconstructValue, DefineEvent, ExpandTransition, ExpandTransitionOptions, FORM_EMPTY_CONTENT, FormComponentProps, FormContextModel, FormContextProps, Index, NAME_SPACE, Null, PresetRule, PropsWithServerQuery, RenderReturn, Tween, TweenConfig, Undef, ValidateRule, Validator, ValidatorConfig, addClass, bem, createIncrease, createToggle, extractNormalVNodes, getHighlightChunks, getNearestScrollParent, getScrollParents, injectFormContext, isComment, isFragment, isTemplate, isTextNode, makeBEM, middleProxy, nextFrame, provideFormContext, removeClass, removeStyles, scrollIntoContainerView, setStyles, shallowComputed, withUnit, zIndex };
17
+ import { FormContextModel, FormContextProps, FormFieldItem, injectFormContext, provideFormContext } from "./types/form-context.js";
18
+ export { AnimeConfig, BEM, BEMFactory, BreakpointName, CLS_PREFIX, ColorType, ComponentProps, ComponentSize, DeconstructValue, DefineEvent, ExpandTransition, ExpandTransitionOptions, FORM_EMPTY_CONTENT, FormComponentProps, FormContextModel, FormContextProps, FormFieldItem, Index, NAME_SPACE, Null, PropsWithServerQuery, RenderReturn, Tween, TweenConfig, Undef, addClass, bem, createIncrease, createToggle, extractNormalVNodes, getHighlightChunks, getNearestScrollParent, getScrollParents, injectFormContext, isComment, isFragment, isTemplate, isTextNode, makeBEM, middleProxy, nextFrame, provideFormContext, removeClass, removeStyles, scrollIntoContainerView, setStyles, shallowComputed, withUnit, zIndex };
package/dist/index.js CHANGED
@@ -7,11 +7,10 @@ import { getHighlightChunks } from "./dom/highlight.js";
7
7
  import { getNearestScrollParent, getScrollParents, scrollIntoContainerView } from "./dom/position.js";
8
8
  import { createIncrease } from "./helper/create-increase.js";
9
9
  import { zIndex } from "./dom/z-index.js";
10
- import { Validator } from "./form/validate.js";
11
10
  import { createToggle } from "./helper/create-toggle.js";
12
11
  import { Tween } from "./helper/tween.js";
13
12
  import { nextFrame } from "./helper/frame.js";
14
13
  import { extractNormalVNodes, isComment, isFragment, isTemplate, isTextNode, shallowComputed } from "./helper/vue.js";
15
14
  import { middleProxy } from "./reactive/proxy.js";
16
15
  import { injectFormContext, provideFormContext } from "./types/form-context.js";
17
- export { CLS_PREFIX, ExpandTransition, FORM_EMPTY_CONTENT, NAME_SPACE, Tween, Validator, addClass, bem, createIncrease, createToggle, extractNormalVNodes, getHighlightChunks, getNearestScrollParent, getScrollParents, injectFormContext, isComment, isFragment, isTemplate, isTextNode, makeBEM, middleProxy, nextFrame, provideFormContext, removeClass, removeStyles, scrollIntoContainerView, setStyles, shallowComputed, withUnit, zIndex };
16
+ export { CLS_PREFIX, ExpandTransition, FORM_EMPTY_CONTENT, NAME_SPACE, Tween, addClass, bem, createIncrease, createToggle, extractNormalVNodes, getHighlightChunks, getNearestScrollParent, getScrollParents, injectFormContext, isComment, isFragment, isTemplate, isTextNode, makeBEM, middleProxy, nextFrame, provideFormContext, removeClass, removeStyles, scrollIntoContainerView, setStyles, shallowComputed, withUnit, zIndex };
@@ -18,17 +18,25 @@ interface FormContextProps {
18
18
  readonly?: boolean;
19
19
  /** 是否隐藏提示 */
20
20
  noTips?: boolean;
21
- /** 表单数据模型 */
22
- model?: FormContextModel;
21
+ /** 表单数据 */
22
+ model?: Record<string, any>;
23
23
  }
24
24
  type FormPropsLike = Partial<FormContextProps> & Record<string, any>;
25
+ interface FormFieldItem {
26
+ validate: () => Promise<boolean>;
27
+ clearValidate?: () => void;
28
+ }
25
29
  type DIContext = {
26
- /** 表单属性 */formProps: FormPropsLike;
30
+ /** 表单属性 */formProps: FormPropsLike; /** 注册表单字段 */
31
+ registerField: (field: string, item: FormFieldItem) => void; /** 注销表单字段 */
32
+ unregisterField: (field: string) => void; /** 校验指定字段,未传 keys 时校验全部已注册字段 */
33
+ validateFields?: (keys?: string[]) => Promise<boolean>; /** 是否需要校验 */
34
+ shouldValidate?: () => boolean;
27
35
  };
28
- declare function provideFormContext<T extends FormPropsLike>(props: T): void;
36
+ declare function provideFormContext(context: DIContext): void;
29
37
  declare function injectFormContext(): {
30
38
  /** 是否在表单中 */inForm: boolean;
31
39
  } & Partial<DIContext>;
32
40
  //#endregion
33
- export { FormContextModel, FormContextProps, injectFormContext, provideFormContext };
41
+ export { FormContextModel, FormContextProps, FormFieldItem, injectFormContext, provideFormContext };
34
42
  //# sourceMappingURL=form-context.d.ts.map
@@ -1,8 +1,8 @@
1
1
  import { inject, provide } from "vue";
2
2
  //#region src/types/form-context.ts
3
3
  const FormComponentDIKey = Symbol("FormComponentDIKey");
4
- function provideFormContext(props) {
5
- if (props) provide(FormComponentDIKey, { formProps: props });
4
+ function provideFormContext(context) {
5
+ provide(FormComponentDIKey, context);
6
6
  }
7
7
  function injectFormContext() {
8
8
  const context = inject(FormComponentDIKey, void 0) || {};
@@ -1 +1 @@
1
- {"version":3,"file":"form-context.js","names":[],"sources":["../../src/types/form-context.ts"],"sourcesContent":["import { type InjectionKey, inject, provide } from 'vue'\n\nimport type { ComponentSize } from './component-common'\n\nexport interface FormContextModel {\n errors: Map<any, string[] | undefined>\n fields: Record<string, { required?: unknown }>\n}\n\nexport interface FormContextProps {\n /** 表单列宽 */\n labelWidth?: string | number\n /** 表单尺寸 */\n size?: ComponentSize\n /** 是否禁用 */\n disabled?: boolean\n /** 是否只读 */\n readonly?: boolean\n /** 是否隐藏提示 */\n noTips?: boolean\n /** 表单数据模型 */\n model?: FormContextModel\n}\n\ntype FormPropsLike = Partial<FormContextProps> & Record<string, any>\n\ntype DIContext = {\n /** 表单属性 */\n formProps: FormPropsLike\n}\n\nconst FormComponentDIKey: InjectionKey<DIContext> = Symbol('FormComponentDIKey')\n\nexport function provideFormContext<T extends FormPropsLike>(props: T): void {\n if (props) {\n provide(FormComponentDIKey, { formProps: props })\n }\n}\n\nexport function injectFormContext(): {\n /** 是否在表单中 */\n inForm: boolean\n} & Partial<DIContext> {\n const context = inject(FormComponentDIKey, undefined) || {}\n return { inForm: !!context, ...context }\n}\n"],"mappings":";;AA+BA,MAAM,qBAA8C,OAAO,oBAAoB;AAE/E,SAAgB,mBAA4C,OAAgB;CAC1E,IAAI,OACF,QAAQ,oBAAoB,EAAE,WAAW,MAAM,CAAC;AAEpD;AAEA,SAAgB,oBAGO;CACrB,MAAM,UAAU,OAAO,oBAAoB,KAAA,CAAS,KAAK,CAAC;CAC1D,OAAO;EAAE,QAAQ,CAAC,CAAC;EAAS,GAAG;CAAQ;AACzC"}
1
+ {"version":3,"file":"form-context.js","names":[],"sources":["../../src/types/form-context.ts"],"sourcesContent":["import { type InjectionKey, inject, provide } from 'vue'\n\nimport type { ComponentSize } from './component-common'\n\nexport interface FormContextModel {\n errors: Map<any, string[] | undefined>\n fields: Record<string, { required?: unknown }>\n}\n\nexport interface FormContextProps {\n /** 表单列宽 */\n labelWidth?: string | number\n /** 表单尺寸 */\n size?: ComponentSize\n /** 是否禁用 */\n disabled?: boolean\n /** 是否只读 */\n readonly?: boolean\n /** 是否隐藏提示 */\n noTips?: boolean\n /** 表单数据 */\n model?: Record<string, any>\n}\n\ntype FormPropsLike = Partial<FormContextProps> & Record<string, any>\n\nexport interface FormFieldItem {\n validate: () => Promise<boolean>\n clearValidate?: () => void\n}\n\ntype DIContext = {\n /** 表单属性 */\n formProps: FormPropsLike\n /** 注册表单字段 */\n registerField: (field: string, item: FormFieldItem) => void\n /** 注销表单字段 */\n unregisterField: (field: string) => void\n /** 校验指定字段,未传 keys 时校验全部已注册字段 */\n validateFields?: (keys?: string[]) => Promise<boolean>\n /** 是否需要校验 */\n shouldValidate?: () => boolean\n}\n\nconst FormComponentDIKey: InjectionKey<DIContext> = Symbol('FormComponentDIKey')\n\nexport function provideFormContext(context: DIContext): void {\n provide(FormComponentDIKey, context)\n}\n\nexport function injectFormContext(): {\n /** 是否在表单中 */\n inForm: boolean\n} & Partial<DIContext> {\n const context = inject(FormComponentDIKey, undefined) || {}\n return { inForm: !!context, ...context }\n}\n"],"mappings":";;AA4CA,MAAM,qBAA8C,OAAO,oBAAoB;AAE/E,SAAgB,mBAAmB,SAA0B;CAC3D,QAAQ,oBAAoB,OAAO;AACrC;AAEA,SAAgB,oBAGO;CACrB,MAAM,UAAU,OAAO,oBAAoB,KAAA,CAAS,KAAK,CAAC;CAC1D,OAAO;EAAE,QAAQ,CAAC,CAAC;EAAS,GAAG;CAAQ;AACzC"}
@@ -1,5 +1,4 @@
1
- import { Data, PresetRule, ValidateRule, ValidatorConfig } from "./utils/form/validate.js";
2
1
  import { DeconstructValue, DefineEvent, Index, Null, RenderReturn, Undef } from "./helper.js";
3
2
  import { BreakpointName, ColorType, ComponentProps, ComponentSize, FormComponentProps, PropsWithServerQuery } from "./component-common.js";
4
- import { FormContextModel, FormContextProps, injectFormContext, provideFormContext } from "./form-context.js";
5
- export { BreakpointName, ColorType, ComponentProps, ComponentSize, Data, DeconstructValue, DefineEvent, FormComponentProps, FormContextModel, FormContextProps, Index, Null, PresetRule, PropsWithServerQuery, RenderReturn, Undef, ValidateRule, ValidatorConfig, injectFormContext, provideFormContext };
3
+ import { FormContextModel, FormContextProps, FormFieldItem, injectFormContext, provideFormContext } from "./form-context.js";
4
+ export { BreakpointName, ColorType, ComponentProps, ComponentSize, DeconstructValue, DefineEvent, FormComponentProps, FormContextModel, FormContextProps, FormFieldItem, Index, Null, PropsWithServerQuery, RenderReturn, Undef, injectFormContext, provideFormContext };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veltra/utils",
3
- "version": "1.1.35",
3
+ "version": "1.2.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
package/src/index.ts CHANGED
@@ -10,8 +10,6 @@ export * from './dom/style'
10
10
 
11
11
  export * from './dom/z-index'
12
12
 
13
- export * from './form/validate'
14
-
15
13
  export * from './helper/create-increase'
16
14
 
17
15
  export * from './helper/create-toggle'
@@ -18,23 +18,34 @@ export interface FormContextProps {
18
18
  readonly?: boolean
19
19
  /** 是否隐藏提示 */
20
20
  noTips?: boolean
21
- /** 表单数据模型 */
22
- model?: FormContextModel
21
+ /** 表单数据 */
22
+ model?: Record<string, any>
23
23
  }
24
24
 
25
25
  type FormPropsLike = Partial<FormContextProps> & Record<string, any>
26
26
 
27
+ export interface FormFieldItem {
28
+ validate: () => Promise<boolean>
29
+ clearValidate?: () => void
30
+ }
31
+
27
32
  type DIContext = {
28
33
  /** 表单属性 */
29
34
  formProps: FormPropsLike
35
+ /** 注册表单字段 */
36
+ registerField: (field: string, item: FormFieldItem) => void
37
+ /** 注销表单字段 */
38
+ unregisterField: (field: string) => void
39
+ /** 校验指定字段,未传 keys 时校验全部已注册字段 */
40
+ validateFields?: (keys?: string[]) => Promise<boolean>
41
+ /** 是否需要校验 */
42
+ shouldValidate?: () => boolean
30
43
  }
31
44
 
32
45
  const FormComponentDIKey: InjectionKey<DIContext> = Symbol('FormComponentDIKey')
33
46
 
34
- export function provideFormContext<T extends FormPropsLike>(props: T): void {
35
- if (props) {
36
- provide(FormComponentDIKey, { formProps: props })
37
- }
47
+ export function provideFormContext(context: DIContext): void {
48
+ provide(FormComponentDIKey, context)
38
49
  }
39
50
 
40
51
  export function injectFormContext(): {
@@ -1,4 +1,3 @@
1
1
  export * from './helper'
2
2
  export * from './component-common'
3
3
  export * from './form-context'
4
- export * from './utils/form/validate'
@@ -1,33 +0,0 @@
1
- import { Data, ValidateRule, ValidatorConfig } from "../types/utils/form/validate.js";
2
-
3
- //#region src/form/validate.d.ts
4
- /** */
5
- declare class Validator<Rules extends Record<string, ValidateRule> = Record<string, ValidateRule>, Field extends keyof Rules = keyof Rules> {
6
- protected rules: Rules;
7
- private config?;
8
- constructor(rules: Rules, config?: ValidatorConfig);
9
- /** 是否存在规则 */
10
- private get existRules();
11
- /**
12
- * 校验单条数据
13
- * @param data 数据
14
- */
15
- private validateSingleData;
16
- private validateValue;
17
- private validateValueLazy;
18
- /**
19
- * 校验多条数据
20
- * @param field 需要校验的字段
21
- */
22
- private validateManyData;
23
- /**
24
- * 校验
25
- * @param data 数据
26
- * @param fields 字段
27
- * @returns
28
- */
29
- validate(data: Data, fields?: Field | Field[]): Promise<{ [key in Field]?: string[] }>;
30
- }
31
- //#endregion
32
- export { Validator };
33
- //# sourceMappingURL=validate.d.ts.map
@@ -1,197 +0,0 @@
1
- import { o } from "@cat-kit/core";
2
- //#region src/form/validate.ts
3
- const isEmpty = (value) => {
4
- return value === null || value === void 0;
5
- };
6
- const presetRules = {
7
- email(v) {
8
- if (!/^([\w_-]+)@([\w-]+[.]?)*[\w]+\.[a-zA-Z]{2,10}$/.test(v)) return "邮箱格式不正确";
9
- },
10
- phone(v) {
11
- if (!/^\d{11}$/.test(v)) return "手机号格式不正确";
12
- },
13
- num(v) {
14
- if (!/^\d+$/.test(v)) return "数字格式不正确";
15
- },
16
- url(v) {
17
- if (!/^(ftp|https?):\/\/([\w_-]+)\.([\w-]+[.]?)*[\w]+\.[a-zA-Z]{2,10}(.*)/.test(v)) return "链接格式不正确";
18
- },
19
- idCard(v) {
20
- if (!/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/.test(v)) return "身份证格式不正确";
21
- }
22
- };
23
- /** 预设规则 */
24
- const ruleTypes = {
25
- required(value, required) {
26
- if (required === false) return;
27
- const errMsg = typeof required === "string" ? required : "该项不能为空";
28
- if (isEmpty(value)) return errMsg;
29
- if (Array.isArray(value) && !value.length) return errMsg;
30
- if (typeof value === "string" && !value) return errMsg;
31
- },
32
- min(value, rule) {
33
- if (isEmpty(value)) return;
34
- let _rule = Array.isArray(rule) ? rule[0] : rule;
35
- let errMsg = Array.isArray(rule) ? rule[1] : `该项必须大于等于${_rule}`;
36
- if (typeof value !== "number") return `${value}不是一个数字`;
37
- if (value < _rule) return errMsg;
38
- },
39
- max(value, rule) {
40
- if (isEmpty(value)) return;
41
- let _rule = Array.isArray(rule) ? rule[0] : rule;
42
- let errMsg = Array.isArray(rule) ? rule[1] : `该项必须小于等于${_rule}`;
43
- if (typeof value !== "number") return `${value}不是一个数字`;
44
- if (value > _rule) return errMsg;
45
- },
46
- minLen(value, rule) {
47
- if (isEmpty(value)) return;
48
- let _rule = Array.isArray(rule) ? rule[0] : rule;
49
- let errMsg = Array.isArray(rule) ? rule[1] : `该项长度必须大于等于${_rule}`;
50
- if (!Array.isArray(value) && typeof value !== "string") return `${value}不是一个字符串或数组`;
51
- if (value.length < _rule) return errMsg;
52
- },
53
- maxLen(value, rule) {
54
- if (isEmpty(value)) return;
55
- let _rule = Array.isArray(rule) ? rule[0] : rule;
56
- let errMsg = Array.isArray(rule) ? rule[1] : `该项长度必须小于等于:${_rule}`;
57
- if (!Array.isArray(value) && typeof value !== "string") return `${value}不是一个字符串或数组`;
58
- if (value.length > _rule) return errMsg;
59
- },
60
- match(value, rule) {
61
- if (isEmpty(value) || value === "") return;
62
- if (typeof rule === "string") {
63
- if (!rule) return;
64
- rule = new RegExp(rule);
65
- }
66
- let _rule = Array.isArray(rule) ? rule[0] : rule;
67
- let errMsg = Array.isArray(rule) ? rule[1] : `该项不匹配正则:${_rule}`;
68
- if (typeof value !== "string") return `${value}不是一个字符串`;
69
- if (!_rule.test(value)) return errMsg;
70
- },
71
- preset(value, rule) {
72
- if (isEmpty(value) || value === "" || !rule) return;
73
- if (typeof value !== "string") return `${value}不是一个字符串`;
74
- const ruleValidator = presetRules[rule];
75
- return ruleValidator(value);
76
- }
77
- };
78
- /** */
79
- var Validator = class {
80
- rules;
81
- config;
82
- constructor(rules, config) {
83
- this.rules = rules;
84
- if (config) this.config = config;
85
- }
86
- /** 是否存在规则 */
87
- get existRules() {
88
- for (const _ in this.rules) return true;
89
- return false;
90
- }
91
- /**
92
- * 校验单条数据
93
- * @param data 数据
94
- */
95
- async validateSingleData(data, fields) {
96
- const fieldErrors = {};
97
- if (!this.existRules) return fieldErrors;
98
- const lazy = this.config?.lazy ?? true;
99
- fields = fields ? Array.isArray(fields) ? fields : [fields] : Object.keys(this.rules);
100
- if (lazy) {
101
- for (let i = 0; i < fields.length; i++) {
102
- const field = fields[i];
103
- const errors = await this.validateValueLazy(data, field);
104
- if (errors.length === 0) continue;
105
- fieldErrors[field] = errors;
106
- }
107
- return fieldErrors;
108
- } else {
109
- for (let i = 0; i < fields.length; i++) {
110
- const field = fields[i];
111
- const errors = await this.validateValue(data, field);
112
- if (errors.length === 0) continue;
113
- fieldErrors[field] = errors;
114
- }
115
- return fieldErrors;
116
- }
117
- }
118
- async validateValue(data, field) {
119
- const rules = this.rules[field];
120
- const value = o(data).get(field);
121
- const { validator, required, ...normalRules } = rules;
122
- let errors = [];
123
- if (required) {
124
- const err = ruleTypes.required(value, required);
125
- err && errors.push(err);
126
- }
127
- for (const ruleKey in normalRules) {
128
- const validate = ruleTypes[ruleKey];
129
- if (!validate) continue;
130
- const err = validate(value, normalRules[ruleKey]);
131
- err && errors.push(err);
132
- }
133
- if (validator) {
134
- const err = await validator(value, data);
135
- err && errors.push(err);
136
- }
137
- return errors;
138
- }
139
- async validateValueLazy(data, field) {
140
- const rules = this.rules[field];
141
- const value = o(data).get(field);
142
- let errors = [];
143
- if (!rules) return errors;
144
- const { validator, required, ...normalRules } = rules;
145
- if (required) {
146
- const err = ruleTypes.required(value, required);
147
- if (err) {
148
- errors.push(err);
149
- return errors;
150
- }
151
- }
152
- for (const ruleKey in normalRules) {
153
- const validate = ruleTypes[ruleKey];
154
- if (!validate) continue;
155
- const err = validate(value, normalRules[ruleKey]);
156
- if (err) {
157
- errors.push(err);
158
- return errors;
159
- }
160
- }
161
- if (validator) {
162
- const err = await validator(value, data);
163
- if (err) {
164
- errors.push(err);
165
- return errors;
166
- }
167
- }
168
- return errors;
169
- }
170
- /**
171
- * 校验多条数据
172
- * @param field 需要校验的字段
173
- */
174
- async validateManyData(data, field) {
175
- let i = 0;
176
- while (i < data.length) {
177
- const item = data[i];
178
- const fieldErrors = await this.validateSingleData(item, field);
179
- if (Object.keys(fieldErrors).length > 0) return fieldErrors;
180
- i++;
181
- }
182
- return {};
183
- }
184
- /**
185
- * 校验
186
- * @param data 数据
187
- * @param fields 字段
188
- * @returns
189
- */
190
- async validate(data, fields) {
191
- return Array.isArray(data) ? this.validateManyData(data, fields) : this.validateSingleData(data, fields);
192
- }
193
- };
194
- //#endregion
195
- export { Validator };
196
-
197
- //# sourceMappingURL=validate.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validate.js","names":[],"sources":["../../src/form/validate.ts"],"sourcesContent":["import { o } from '@cat-kit/core'\n\nimport type { Undef } from '../types/helper'\nimport type { ValidateRule, Data, ValidatorConfig, PresetRule } from '../types/utils/form/validate'\n\nconst isEmpty = (value: any): value is null | undefined => {\n return value === null || value === undefined\n}\n\nconst presetRules: Record<PresetRule, (value: string) => string | undefined> = {\n email(v) {\n const re = /^([\\w_-]+)@([\\w-]+[.]?)*[\\w]+\\.[a-zA-Z]{2,10}$/\n if (!re.test(v)) {\n return '邮箱格式不正确'\n }\n },\n phone(v) {\n const re = /^\\d{11}$/\n if (!re.test(v)) {\n return '手机号格式不正确'\n }\n },\n num(v) {\n const re = /^\\d+$/\n if (!re.test(v)) {\n return '数字格式不正确'\n }\n },\n url(v) {\n const re = /^(ftp|https?):\\/\\/([\\w_-]+)\\.([\\w-]+[.]?)*[\\w]+\\.[a-zA-Z]{2,10}(.*)/\n if (!re.test(v)) {\n return '链接格式不正确'\n }\n },\n\n idCard(v) {\n const re = /^(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9]|X)$/\n if (!re.test(v)) {\n return '身份证格式不正确'\n }\n }\n}\n\n/** 预设规则 */\nconst ruleTypes = {\n required(value: any, required: ValidateRule['required']): Undef<string> {\n if (required === false) return\n\n const errMsg = typeof required === 'string' ? required : '该项不能为空'\n if (isEmpty(value)) return errMsg\n\n if (Array.isArray(value) && !value.length) return errMsg\n if (typeof value === 'string' && !value) return errMsg\n },\n min(value: any, rule: ValidateRule['min']): Undef<string> {\n if (isEmpty(value)) return\n let _rule = Array.isArray(rule) ? rule[0] : rule!\n let errMsg = Array.isArray(rule) ? rule[1] : `该项必须大于等于${_rule}`\n if (typeof value !== 'number') return `${value}不是一个数字`\n if (value < _rule) return errMsg\n },\n max(value: any, rule: ValidateRule['max']): Undef<string> {\n if (isEmpty(value)) return\n let _rule = Array.isArray(rule) ? rule[0] : rule!\n let errMsg = Array.isArray(rule) ? rule[1] : `该项必须小于等于${_rule}`\n if (typeof value !== 'number') return `${value}不是一个数字`\n if (value > _rule) return errMsg\n },\n\n minLen(value: any, rule: ValidateRule['minLen']): Undef<string> {\n if (isEmpty(value)) return\n let _rule = Array.isArray(rule) ? rule[0] : rule!\n let errMsg = Array.isArray(rule) ? rule[1] : `该项长度必须大于等于${_rule}`\n if (!Array.isArray(value) && typeof value !== 'string') return `${value}不是一个字符串或数组`\n if (value.length < _rule) return errMsg\n },\n maxLen(value: any, rule: ValidateRule['maxLen']): Undef<string> {\n if (isEmpty(value)) return\n let _rule = Array.isArray(rule) ? rule[0] : rule!\n let errMsg = Array.isArray(rule) ? rule[1] : `该项长度必须小于等于:${_rule}`\n if (!Array.isArray(value) && typeof value !== 'string') return `${value}不是一个字符串或数组`\n if (value.length > _rule) return errMsg\n },\n match(value: any, rule: ValidateRule['match']): Undef<string> {\n if (isEmpty(value) || value === '') return\n if (typeof rule === 'string') {\n if (!rule) return\n rule = new RegExp(rule)\n }\n let _rule = Array.isArray(rule) ? rule[0] : rule!\n let errMsg = Array.isArray(rule) ? rule[1] : `该项不匹配正则:${_rule}`\n if (typeof value !== 'string') return `${value}不是一个字符串`\n if (!_rule.test(value)) return errMsg\n },\n preset(value: any, rule: ValidateRule['preset']): Undef<string> {\n if (isEmpty(value) || value === '' || !rule) return\n if (typeof value !== 'string') return `${value}不是一个字符串`\n const ruleValidator = presetRules[rule]\n return ruleValidator(value)\n }\n}\n/** */\nexport class Validator<\n Rules extends Record<string, ValidateRule> = Record<string, ValidateRule>,\n Field extends keyof Rules = keyof Rules\n> {\n protected rules: Rules\n\n private config?: ValidatorConfig\n\n constructor(rules: Rules, config?: ValidatorConfig) {\n this.rules = rules\n if (config) {\n this.config = config\n }\n }\n\n /** 是否存在规则 */\n private get existRules() {\n for (const _ in this.rules) {\n return true\n }\n return false\n }\n\n /**\n * 校验单条数据\n * @param data 数据\n */\n private async validateSingleData(\n data: Record<any, any>,\n fields?: Field | Field[]\n ): Promise<{ [key in Field]?: string[] }> {\n const fieldErrors: { [key in Field]?: string[] } = {}\n\n if (!this.existRules) return fieldErrors\n\n const lazy = this.config?.lazy ?? true\n\n fields = fields\n ? Array.isArray(fields)\n ? fields\n : [fields]\n : (Object.keys(this.rules) as Field[])\n\n // 懒校验,当有一个规则不通过,剩下的规则不再校验\n if (lazy) {\n // 校验字段\n for (let i = 0; i < fields.length; i++) {\n const field = fields[i]!\n // oxlint-disable-next-line no-await-in-loop -- 懒校验需按字段顺序短路\n const errors = await this.validateValueLazy(data, field)\n if (errors.length === 0) continue\n fieldErrors[field] = errors\n }\n return fieldErrors\n } else {\n // 校验字段\n for (let i = 0; i < fields.length; i++) {\n const field = fields[i]!\n // oxlint-disable-next-line no-await-in-loop -- 按字段顺序校验以便尽早收集错误\n const errors = await this.validateValue(data, field)\n if (errors.length === 0) continue\n fieldErrors[field] = errors\n }\n\n return fieldErrors\n }\n }\n\n private async validateValue(data: Record<any, any>, field: Field) {\n const rules = this.rules[field]!\n const value = o(data).get(field as string)\n\n const { validator, required, ...normalRules } = rules\n\n let errors: string[] = []\n\n // 必填要先去校验\n if (required) {\n const err = ruleTypes.required(value, required)\n err && errors.push(err)\n }\n\n // 校验规则\n for (const ruleKey in normalRules) {\n const validate = ruleTypes[ruleKey]\n if (!validate) continue\n const err = validate(value, normalRules[ruleKey])\n err && errors.push(err)\n }\n\n // 自定义校验\n if (validator) {\n const err = await validator(value, data)\n err && errors.push(err)\n }\n\n return errors\n }\n\n private async validateValueLazy(data: Record<any, any>, field: Field): Promise<string[]> {\n const rules = this.rules[field]\n const value = o(data).get(field as string)\n let errors: string[] = []\n\n if (!rules) return errors\n\n const { validator, required, ...normalRules } = rules\n\n // 必填要先去校验\n if (required) {\n const err = ruleTypes.required(value, required)\n if (err) {\n errors.push(err)\n return errors\n }\n }\n\n // 校验规则\n for (const ruleKey in normalRules) {\n const validate = ruleTypes[ruleKey]\n if (!validate) continue\n\n const err = validate(value, normalRules[ruleKey])\n\n if (err) {\n errors.push(err)\n return errors\n }\n }\n\n // 自定义校验最火校验\n if (validator) {\n const err = await validator(value, data)\n if (err) {\n errors.push(err)\n return errors\n }\n }\n\n return errors\n }\n\n /**\n * 校验多条数据\n * @param field 需要校验的字段\n */\n private async validateManyData(\n data: Data,\n field?: Field | Field[]\n ): Promise<{ [key in Field]?: string[] }> {\n let i = 0\n while (i < data.length) {\n const item = data[i]!\n // oxlint-disable-next-line no-await-in-loop -- 多条数据校验命中首条错误即返回\n const fieldErrors = await this.validateSingleData(item, field)\n if (Object.keys(fieldErrors).length > 0) {\n return fieldErrors\n }\n i++\n }\n\n return {}\n }\n\n /**\n * 校验\n * @param data 数据\n * @param fields 字段\n * @returns\n */\n async validate(data: Data, fields?: Field | Field[]): Promise<{ [key in Field]?: string[] }> {\n return Array.isArray(data)\n ? this.validateManyData(data, fields)\n : this.validateSingleData(data, fields)\n }\n}\n"],"mappings":"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"}
@@ -1,34 +0,0 @@
1
- //#region src/types/utils/form/validate.d.ts
2
- type Data = Record<string, any>;
3
- type PresetRule = 'email' | 'phone' | 'num' | 'url' | 'idCard';
4
- /** 字段校验规则 */
5
- interface ValidateRule {
6
- /** 是否必填 */
7
- required?: boolean | string;
8
- /** 长度单位 */
9
- length?: number | [number, string];
10
- /** 最小值 */
11
- min?: number | [number, string];
12
- /** 最大值 */
13
- max?: number | [number, string];
14
- /** 最小长度 */
15
- minLen?: number | [number, string];
16
- /** 最大长度 */
17
- maxLen?: number | [number, string];
18
- /** 匹配 */
19
- match?: RegExp | [RegExp, string] | string;
20
- /** 预设 */
21
- preset?: PresetRule;
22
- /** 自定义校验 */
23
- validator?: (value: any, data: Data) => Promise<string> | string;
24
- }
25
- interface ValidatorConfig {
26
- /**
27
- * 是否懒校验,为true时在任意一个字段的的任意规则校验不通过时立马结束校验,性能稍微高一点,但是不能得出所有的错误
28
- * @default true
29
- */
30
- lazy?: boolean;
31
- }
32
- //#endregion
33
- export { Data, PresetRule, ValidateRule, ValidatorConfig };
34
- //# sourceMappingURL=validate.d.ts.map
@@ -1,278 +0,0 @@
1
- import { o } from '@cat-kit/core'
2
-
3
- import type { Undef } from '../types/helper'
4
- import type { ValidateRule, Data, ValidatorConfig, PresetRule } from '../types/utils/form/validate'
5
-
6
- const isEmpty = (value: any): value is null | undefined => {
7
- return value === null || value === undefined
8
- }
9
-
10
- const presetRules: Record<PresetRule, (value: string) => string | undefined> = {
11
- email(v) {
12
- const re = /^([\w_-]+)@([\w-]+[.]?)*[\w]+\.[a-zA-Z]{2,10}$/
13
- if (!re.test(v)) {
14
- return '邮箱格式不正确'
15
- }
16
- },
17
- phone(v) {
18
- const re = /^\d{11}$/
19
- if (!re.test(v)) {
20
- return '手机号格式不正确'
21
- }
22
- },
23
- num(v) {
24
- const re = /^\d+$/
25
- if (!re.test(v)) {
26
- return '数字格式不正确'
27
- }
28
- },
29
- url(v) {
30
- const re = /^(ftp|https?):\/\/([\w_-]+)\.([\w-]+[.]?)*[\w]+\.[a-zA-Z]{2,10}(.*)/
31
- if (!re.test(v)) {
32
- return '链接格式不正确'
33
- }
34
- },
35
-
36
- idCard(v) {
37
- const re = /^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/
38
- if (!re.test(v)) {
39
- return '身份证格式不正确'
40
- }
41
- }
42
- }
43
-
44
- /** 预设规则 */
45
- const ruleTypes = {
46
- required(value: any, required: ValidateRule['required']): Undef<string> {
47
- if (required === false) return
48
-
49
- const errMsg = typeof required === 'string' ? required : '该项不能为空'
50
- if (isEmpty(value)) return errMsg
51
-
52
- if (Array.isArray(value) && !value.length) return errMsg
53
- if (typeof value === 'string' && !value) return errMsg
54
- },
55
- min(value: any, rule: ValidateRule['min']): Undef<string> {
56
- if (isEmpty(value)) return
57
- let _rule = Array.isArray(rule) ? rule[0] : rule!
58
- let errMsg = Array.isArray(rule) ? rule[1] : `该项必须大于等于${_rule}`
59
- if (typeof value !== 'number') return `${value}不是一个数字`
60
- if (value < _rule) return errMsg
61
- },
62
- max(value: any, rule: ValidateRule['max']): Undef<string> {
63
- if (isEmpty(value)) return
64
- let _rule = Array.isArray(rule) ? rule[0] : rule!
65
- let errMsg = Array.isArray(rule) ? rule[1] : `该项必须小于等于${_rule}`
66
- if (typeof value !== 'number') return `${value}不是一个数字`
67
- if (value > _rule) return errMsg
68
- },
69
-
70
- minLen(value: any, rule: ValidateRule['minLen']): Undef<string> {
71
- if (isEmpty(value)) return
72
- let _rule = Array.isArray(rule) ? rule[0] : rule!
73
- let errMsg = Array.isArray(rule) ? rule[1] : `该项长度必须大于等于${_rule}`
74
- if (!Array.isArray(value) && typeof value !== 'string') return `${value}不是一个字符串或数组`
75
- if (value.length < _rule) return errMsg
76
- },
77
- maxLen(value: any, rule: ValidateRule['maxLen']): Undef<string> {
78
- if (isEmpty(value)) return
79
- let _rule = Array.isArray(rule) ? rule[0] : rule!
80
- let errMsg = Array.isArray(rule) ? rule[1] : `该项长度必须小于等于:${_rule}`
81
- if (!Array.isArray(value) && typeof value !== 'string') return `${value}不是一个字符串或数组`
82
- if (value.length > _rule) return errMsg
83
- },
84
- match(value: any, rule: ValidateRule['match']): Undef<string> {
85
- if (isEmpty(value) || value === '') return
86
- if (typeof rule === 'string') {
87
- if (!rule) return
88
- rule = new RegExp(rule)
89
- }
90
- let _rule = Array.isArray(rule) ? rule[0] : rule!
91
- let errMsg = Array.isArray(rule) ? rule[1] : `该项不匹配正则:${_rule}`
92
- if (typeof value !== 'string') return `${value}不是一个字符串`
93
- if (!_rule.test(value)) return errMsg
94
- },
95
- preset(value: any, rule: ValidateRule['preset']): Undef<string> {
96
- if (isEmpty(value) || value === '' || !rule) return
97
- if (typeof value !== 'string') return `${value}不是一个字符串`
98
- const ruleValidator = presetRules[rule]
99
- return ruleValidator(value)
100
- }
101
- }
102
- /** */
103
- export class Validator<
104
- Rules extends Record<string, ValidateRule> = Record<string, ValidateRule>,
105
- Field extends keyof Rules = keyof Rules
106
- > {
107
- protected rules: Rules
108
-
109
- private config?: ValidatorConfig
110
-
111
- constructor(rules: Rules, config?: ValidatorConfig) {
112
- this.rules = rules
113
- if (config) {
114
- this.config = config
115
- }
116
- }
117
-
118
- /** 是否存在规则 */
119
- private get existRules() {
120
- for (const _ in this.rules) {
121
- return true
122
- }
123
- return false
124
- }
125
-
126
- /**
127
- * 校验单条数据
128
- * @param data 数据
129
- */
130
- private async validateSingleData(
131
- data: Record<any, any>,
132
- fields?: Field | Field[]
133
- ): Promise<{ [key in Field]?: string[] }> {
134
- const fieldErrors: { [key in Field]?: string[] } = {}
135
-
136
- if (!this.existRules) return fieldErrors
137
-
138
- const lazy = this.config?.lazy ?? true
139
-
140
- fields = fields
141
- ? Array.isArray(fields)
142
- ? fields
143
- : [fields]
144
- : (Object.keys(this.rules) as Field[])
145
-
146
- // 懒校验,当有一个规则不通过,剩下的规则不再校验
147
- if (lazy) {
148
- // 校验字段
149
- for (let i = 0; i < fields.length; i++) {
150
- const field = fields[i]!
151
- // oxlint-disable-next-line no-await-in-loop -- 懒校验需按字段顺序短路
152
- const errors = await this.validateValueLazy(data, field)
153
- if (errors.length === 0) continue
154
- fieldErrors[field] = errors
155
- }
156
- return fieldErrors
157
- } else {
158
- // 校验字段
159
- for (let i = 0; i < fields.length; i++) {
160
- const field = fields[i]!
161
- // oxlint-disable-next-line no-await-in-loop -- 按字段顺序校验以便尽早收集错误
162
- const errors = await this.validateValue(data, field)
163
- if (errors.length === 0) continue
164
- fieldErrors[field] = errors
165
- }
166
-
167
- return fieldErrors
168
- }
169
- }
170
-
171
- private async validateValue(data: Record<any, any>, field: Field) {
172
- const rules = this.rules[field]!
173
- const value = o(data).get(field as string)
174
-
175
- const { validator, required, ...normalRules } = rules
176
-
177
- let errors: string[] = []
178
-
179
- // 必填要先去校验
180
- if (required) {
181
- const err = ruleTypes.required(value, required)
182
- err && errors.push(err)
183
- }
184
-
185
- // 校验规则
186
- for (const ruleKey in normalRules) {
187
- const validate = ruleTypes[ruleKey]
188
- if (!validate) continue
189
- const err = validate(value, normalRules[ruleKey])
190
- err && errors.push(err)
191
- }
192
-
193
- // 自定义校验
194
- if (validator) {
195
- const err = await validator(value, data)
196
- err && errors.push(err)
197
- }
198
-
199
- return errors
200
- }
201
-
202
- private async validateValueLazy(data: Record<any, any>, field: Field): Promise<string[]> {
203
- const rules = this.rules[field]
204
- const value = o(data).get(field as string)
205
- let errors: string[] = []
206
-
207
- if (!rules) return errors
208
-
209
- const { validator, required, ...normalRules } = rules
210
-
211
- // 必填要先去校验
212
- if (required) {
213
- const err = ruleTypes.required(value, required)
214
- if (err) {
215
- errors.push(err)
216
- return errors
217
- }
218
- }
219
-
220
- // 校验规则
221
- for (const ruleKey in normalRules) {
222
- const validate = ruleTypes[ruleKey]
223
- if (!validate) continue
224
-
225
- const err = validate(value, normalRules[ruleKey])
226
-
227
- if (err) {
228
- errors.push(err)
229
- return errors
230
- }
231
- }
232
-
233
- // 自定义校验最火校验
234
- if (validator) {
235
- const err = await validator(value, data)
236
- if (err) {
237
- errors.push(err)
238
- return errors
239
- }
240
- }
241
-
242
- return errors
243
- }
244
-
245
- /**
246
- * 校验多条数据
247
- * @param field 需要校验的字段
248
- */
249
- private async validateManyData(
250
- data: Data,
251
- field?: Field | Field[]
252
- ): Promise<{ [key in Field]?: string[] }> {
253
- let i = 0
254
- while (i < data.length) {
255
- const item = data[i]!
256
- // oxlint-disable-next-line no-await-in-loop -- 多条数据校验命中首条错误即返回
257
- const fieldErrors = await this.validateSingleData(item, field)
258
- if (Object.keys(fieldErrors).length > 0) {
259
- return fieldErrors
260
- }
261
- i++
262
- }
263
-
264
- return {}
265
- }
266
-
267
- /**
268
- * 校验
269
- * @param data 数据
270
- * @param fields 字段
271
- * @returns
272
- */
273
- async validate(data: Data, fields?: Field | Field[]): Promise<{ [key in Field]?: string[] }> {
274
- return Array.isArray(data)
275
- ? this.validateManyData(data, fields)
276
- : this.validateSingleData(data, fields)
277
- }
278
- }
@@ -1,33 +0,0 @@
1
- export type Data = Record<string, any>
2
-
3
- export type PresetRule = 'email' | 'phone' | 'num' | 'url' | 'idCard'
4
-
5
- /** 字段校验规则 */
6
- export interface ValidateRule {
7
- /** 是否必填 */
8
- required?: boolean | string
9
- /** 长度单位 */
10
- length?: number | [number, string]
11
- /** 最小值 */
12
- min?: number | [number, string]
13
- /** 最大值 */
14
- max?: number | [number, string]
15
- /** 最小长度 */
16
- minLen?: number | [number, string]
17
- /** 最大长度 */
18
- maxLen?: number | [number, string]
19
- /** 匹配 */
20
- match?: RegExp | [RegExp, string] | string
21
- /** 预设 */
22
- preset?: PresetRule
23
- /** 自定义校验 */
24
- validator?: (value: any, data: Data) => Promise<string> | string
25
- }
26
-
27
- export interface ValidatorConfig {
28
- /**
29
- * 是否懒校验,为true时在任意一个字段的的任意规则校验不通过时立马结束校验,性能稍微高一点,但是不能得出所有的错误
30
- * @default true
31
- */
32
- lazy?: boolean
33
- }