UNPKG

ph-utils

Version:

js 开发工具集,前后端都可以使用(commonjs和es module)

234 lines (233 loc) 7.62 kB
/** * 数据验证器 */ // 默认的错误提示信息 const defaultMsgs = { mobile: "请输入正确的手机号", same: "两次输入不一致", required: "%s为必填字段", }; const defaultMsg = "请输入正确的数据"; // 一些常用的验证正则 const ruleRegexs = { /** 验证跟其余数据相等的正则,一般用于验证再次输入密码 */ same: /^same:(.+)$/i, /** 验证手机号的正则表达式 */ mobile: /^1[345678]\d{9}$/, /** 非空验证的正则表达式 */ required: /^\S{1}.*/, }; // 规则比对函数 const ruleFns = { /** 验证相等 */ same(val1, val2) { return val2 === val1; }, /** 正则匹配 */ pattern(regex, val) { if (val == null) { return false; } return regex.test(String(val)); }, }; class ValidateError extends Error { constructor(detail, key, message) { super(message); this.name = "ValidateError"; this.key = key; this.detail = detail; } } /** * 数据验证器 */ class Validator { /** * 构造数据验证转换器 * * See {@link https://gitee.com/towardly/ph/wikis/utils/validator|Validator文档}. * * @param schemas 配置验证转换规则 * * @example * * const validator = new Validator([ * { key: 'mobile', rules: ['required', 'mobile'] }, * { key: 'code': rules: /^\d{6}$/, message: '请输入正确的验证码' }, * { key: 'confirmPassword', rules: ['required', 'same:password'] } * ]) * // 验证某一个字段 * validator.validateKey().then(res => {}) */ constructor(schemas) { this.rules = {}; this.addSchemas(schemas); } addSchemas(schemas) { for (let schema of schemas) { this.rules[schema.key] = this._parseSchemaRules(schema); } } addSchema(schema) { this.rules[schema.key] = this._parseSchemaRules(schema); } /** * 进行数据验证 * @param data 待验证的数据 * @param all 是否全部验证, false - 只要验证错误一个则停止验证 * @returns */ async validate(data, all = false) { return new Promise((resolve, reject) => { const detail = {}; let currentKey = undefined; let currentMessage = undefined; for (let key in this.rules) { let errMsg = this._validateRule(this.rules[key], data[key], data); if (errMsg !== "") { errMsg = errMsg.replace("%s", key); detail[key] = errMsg; currentKey = key; currentMessage = errMsg; if (all) break; } } if (currentKey == null) { resolve(true); } else { reject(new ValidateError(detail, currentKey, currentMessage)); } }); } /** * 只验证指定 key 的数据格式 * @param key 指定待验证的 key * @param value 待验证的数据 * @param data 原始数据,当验证确认密码时需要使用 */ async validateKey(key, value, data) { return new Promise((resolve, reject) => { let keyRules = this.rules[key]; if (keyRules == null) { resolve({ key, value }); return; } let errMsg = this._validateRule(keyRules, value, data); if (errMsg !== "") { errMsg = errMsg.replace("%s", key); reject(new ValidateError({ [key]: errMsg }, key, errMsg)); } else { resolve({ key, value }); } }); } _validateRule(rules, value, data) { let errMsg = ""; for (let rule of rules) { // 如果数据为空,则判断是否是必填 if (rule.rule === "required") { if (value == null || !ruleFns.pattern(ruleRegexs.required, value)) { errMsg = rule.message; } } else if (typeof rule.rule === "function") { if (!rule.rule(value)) { errMsg = rule.message; } } else if (rule.sameKey != null) { if (data != null) { if (!ruleFns.same(value, data[rule.sameKey])) { errMsg = rule.message; } } } else { if (!ruleFns.pattern(rule.rule, value)) { errMsg = rule.message; } } if (errMsg !== "") { break; } } return errMsg; } _parseSchemaRules(schema) { // 解析规则 let rules = []; let rule = schema.rules; if (schema.required === true) { rules.push(...this._parseStringRule("required", schema.message)); } if (rule != null) { if (typeof rule === "string") { rules = rules.concat(this._parseStringRule(rule, schema.message)); } else if (rule instanceof Array) { for (let ruleItem of rule) { if (typeof ruleItem === "string") { rules.push(...this._parseStringRule(ruleItem, schema.message)); } else if (ruleItem instanceof RegExp || typeof ruleItem === "function") { rules.push({ rule: ruleItem, message: schema.message || defaultMsg, }); } else { if (typeof ruleItem.rule === "string") { rules.push(...this._parseStringRule(ruleItem.rule, ruleItem.message)); } else { rules.push({ rule: ruleItem.rule, message: ruleItem.message || defaultMsg, }); } } } } else { rules.push({ rule, message: defaultMsg }); } } return rules; } _parseStringRule(rule, ruleErrMsg) { let rules = []; let trule = rule.split("|"); for (let r of trule) { let message = ruleErrMsg; let rrule = null; let sameKey; if (rule === "required") { rrule = "required"; message = message || ruleErrMsg || defaultMsgs.required; } else if (ruleRegexs.same.test(r)) { let m = r.match(ruleRegexs.same); if (m != null) { rrule = ruleRegexs.same; let m = r.match(ruleRegexs.same); if (m != null) { sameKey = m[1]; } message = message || defaultMsgs["same"]; } } else if (Object.hasOwn(ruleRegexs, r)) { rrule = ruleRegexs[r]; message = message || defaultMsgs[r]; } rules.push({ rule: rrule, message: message, sameKey }); } return rules; } } export default Validator;