@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
JavaScript
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();
}