UNPKG

@schema-render/core-react

Version:

Through a set of simple JSON Schema, efficiently build a set of forms.

160 lines (159 loc) 5.9 kB
import { EValidationStatus, VALID_VALIDATION_STATUS } from "../constants"; import { createRegExpByString, hasOwnProperty, templateCompiled } from "./base"; import { isArray, isBoolean, isFunction, isNumber, isPlainObject, isString } from "./checking"; import { pick } from "./tinyLodash"; export class SchemaRulesValidator { static failUK = typeof Symbol === 'function' ? Symbol('SRV') : '$$SRV'; static isValidationError(err) { return isPlainObject(err) && hasOwnProperty(err, SchemaRulesValidator.failUK); } static fail(data) { const result = { [SchemaRulesValidator.failUK]: true }; if (isString(data)) { result.message = data; } else if (isPlainObject(data)) { Object.assign(result, pick(data, 'status', 'message', 'extra')); } if (!result.status) { result.status = EValidationStatus.error; } throw result; } value; rules; locale; globalValidators; globalValidatorParams; constructor(params){ Object.assign(this, params); } setValue(value) { this.value = value; } async validate() { return await this.validateRules(this.rules); } async validateRules(rules) { try { const innerRules = normalizeRules(rules); for (const rule of innerRules){ if (isPlainObject(rule)) { this.validateRuleItem(rule); await this.validateGlobal(rule); } } } catch (err) { if (SchemaRulesValidator.isValidationError(err)) { return pick(err, 'status', 'message', 'extra'); } return { status: EValidationStatus.error, message: (err === null || err === void 0 ? void 0 : err.message) ? err.message : 'CatchError' }; } return { status: EValidationStatus.success }; } // rule 规则 validateRuleItem(rule) { const required = isBoolean(rule.required) ? rule.required : undefined; const len = isNumber(rule.len) ? rule.len : undefined; const min = isNumber(rule.min) ? rule.min : undefined; const max = isNumber(rule.max) ? rule.max : undefined; const fail = SchemaRulesValidator.fail; const { value, locale } = this; if (required && [ undefined, null ].includes(value)) { SchemaRulesValidator.fail(rule.message); } if (rule.type === 'string' && !isString(value) || rule.type === 'number' && !isNumber(value) || rule.type === 'boolean' && !isBoolean(value) || rule.type === 'object' && !isPlainObject(value) || rule.type === 'array' && !isArray(value)) { fail(templateCompiled(locale.typeError, { type: rule.type })); } // Handle string if (isString(value)) { const regexp = createRegExpByString(rule.pattern); if (required && value === '' || len && value.length !== len || min && value.length < min || max && value.length > max || regexp && !regexp.test(value)) { fail(rule.message); } } // Handle number if (isNumber(value)) { if (len && value !== len || min && value < min || max && value > max) { fail(rule.message); } } // Handle array if (isArray(value)) { if (required && value.length === 0 || len && value.length !== len || min && value.length < min || max && value.length > max) { fail(rule.message); } } } // 全局校验器规则 async validateGlobal(rule) { const name = rule.validator; const { globalValidators, globalValidatorParams } = this; if (!name || !globalValidators || !globalValidatorParams) { return; } const gValidator = globalValidators[name]; const maybeFail = (result)=>{ if (result.status !== EValidationStatus.success) { SchemaRulesValidator.fail(result); } }; // rules 规则 if (isValidRules(gValidator)) { // 移除 validator 字段,避免陷入死循环 const result = await this.validateRules(gValidator.filter((o)=>!o.validator)); maybeFail(result); } // 函数校验器 if (isFunction(gValidator)) { const fnResult = await gValidator({ ...globalValidatorParams, value: this.value }); // rules 规则 if (isValidRules(fnResult)) { const result = await this.validateRules(fnResult.filter((o)=>!o.validator)); maybeFail(result); } // 函数返回值规则 if (isValidFunctionResult(fnResult)) { maybeFail({ status: fnResult.status, // 优先使用 rule 指定的错误提示信息 message: rule.message ?? fnResult.message, extra: fnResult.extra }); } } } } export function isValidFunctionResult(result) { return VALID_VALIDATION_STATUS.includes(result === null || result === void 0 ? void 0 : result.status); } export function isValidRules(rules) { return isArray(rules) && !!rules.length; } export function normalizeRules(rules) { const resultRules = []; if (isPlainObject(rules)) { resultRules.push(rules); } else if (isArray(rules)) { resultRules.push(...rules); } return resultRules; } export function validateRules(params) { const validator = new SchemaRulesValidator(params); return validator.validate(); }