UNPKG

utils2

Version:

validator,_,IO,string,date,numer,array

443 lines (425 loc) 16.6 kB
//TODO: i18n /** * √ nullable * √ required 不能为空 * √ int 整数 * √ float 0 -1 -1.5 2 3.5 +4 +4.3 * √ string * √ boolean * √ in * √ range * √ min * √ max * √ length [0,7] (6,12) [7,9) * √ email * √ url * √ date * √ id * * file exe|image * custom * * requiredif:field|int? */ const _ = require('./_'); const moment = require('moment'); class Validator { constructor(o) { this.rules = {}; this.messages = {}; if (o) { this.rules = o.rules; this.messages = o.messages || this.messages[o.lang || 'cn']; } this.parse(); } error(data) { let err = new Error(); err.validate = data; throw err; } /** * 按rules的字段,过滤额外的字段 */ filter(data) { let res = {}; for (let k in this.rules) { let rule = this.rules[k]; if (_.isNumber(data[k]) || this.rules.hasOwnProperty(k) && !_.isEmptyObject(data[k])) { if (rule.boolean && ['true', '1', 'false', '0'].indexOf(data[k] !== -1)) { res[k] = data[k] === 'true' || data[k] === '1' ? true : false; } else { res[k] = data[k]; } } } return res; } /** * 字符串转规则对象 * @param {string} str */ _arr2rule(arr) { let rule = { range: { min: -Infinity, max: Infinity, includeBottom: true, includeTop: true }, length: { min: 0, max: 255 } }; for (let i = 0; i < arr.length; i++) { let kv = /^([a-z]+)[:]?(.*)$/.exec(arr[i].trim().toLowerCase()), v; if (kv === null) { this.error(`${str} 不是有效的规则!`); } v = kv[2]; switch (kv[1]) { case 'nullable': rule.nullable = true; break; case 'required': rule.required = true; break; case 'int': rule.int = true; break; case 'float': rule.float = true; break; case 'boolean': rule.boolean = true; break; case 'date': rule.date = true; break; case 'url': rule.url = true; break; case 'email': rule.email = true; break; case 'file': break; case 'custom': break; case 'min': if (!this.isFloat(v)) { this.error(`${v} 不是有效的数值`); } rule.range.min = v; break; case 'max': if (!this.isFloat(v)) { this.error(`${v} 不是有效的数值`); } rule.range.max = v; break; case 'range': let t = /^(\(|\[)\s*(.+?)\s*,\s*(.+?)\s*(\)|\])$/.exec(v); if (!(t && this.isFloat(t[2]) && this.isFloat(t[3]))) { this.error(`${v} 不是有效的range格式!`) } rule.range.includeBottom = t[1] === '(' ? false : true; rule.range.includeTop = t[4] === ')' ? false : true; rule.range.min = parseFloat(t[2]); rule.range.max = parseFloat(t[3]); break; case 'minlength': if (!this.isInt(v)) { this.error(`${v} 不是有效的正整数!`); } rule.length.min = parseInt(v); break; case 'maxlength': if (!this.isInt(v)) { this.error(`${v} 不是有效的正整数!`); } rule.length.max = parseInt(v); break; case 'length': if (this.isInt(v)) { rule.length.min = rule.length.max = parseInt(v); } else { let t = /^(\(|\[)(\d+),(\d+)(\)|\])$/.exec(kv[2]); if (t) { rule['length']['min'] = parseInt(t[2]); rule['length']['max'] = parseInt(t[3]); } else { this.error('range 不是有效的格式!') } } break; case 'in': rule.in = v.split(',').map(function (s) { if (s.trim() === '') { this.error(`${k} 是空的枚举!`) } return s.trim(); }); break; case 'required_if': rule.required_if = v; break; default: break; } } // 1.nullable和required不能同时存在 if (rule.required == true && rule.nullable == true) { this.error('nullable required'); } if (rule.string === undefined) { delete rule.length; } else if (rule.length.min > rule.length.max) { this.error(`长度范围的下限大于上限!`); } if (rule.int === undefined && rule.float === undefined) { delete rule.range; } else if (rule.range.min > rule.range.max) { this.error(`数值范围的下限大于上限!`); } //TODO:不好做 // if (rule.required_if) { // let v = rule.required_if.split(','); // if (rule[v] === undefined) { // this.error(`${v[0]}`); // } // } return rule; } /** * required|int|min:100|max:200 --> required: true, int: true, max: 10, max: 200 */ parse() { for (let k in this.rules) { // 可以这里处理required_if this.rules[k] = this._arr2rule(this.rules[k].split('|')); } return this; } check(data) { /** * k 字段 * v 值 * kk 验证规则 */ for (let k in this.rules) { let v = data[k]; let rule = this.rules[k]; if (_.isEmpty(v) && rule.nullable || rule.required_if && _.isEmpty(data[rule.required_if])) { delete data[k]; continue; } if (rule.required) { if (_.isEmpty(v)) { this.error({ filed: k, key: 'required' }); } } if (rule.int) { if (!this.isInt(v)) { this.error({ filed: k, key: 'int', value: v }); } data[k] = parseInt(v); } if (rule.float) { if (!this.isFloat(v)) { this.error({ filed: k, key: 'float', value: v }); } data[k] = parseFloat(v); } if (rule.range) { } if (rule.length) { if (v.length < rule.min && v.length > rule.max) { this.error({ filed: k, key: 'length', value: v, rule: rule.length }); } } if (rule.email) { if (!this.isEmail(v)) { this.error({ filed: k, key: 'email', value: v }); } } if (rule.url) { if (!this.isUrl(v)) { this.error({ filed: k, key: 'url', value: v }); } } if (rule.file) { } if (rule.custom) { } if (rule.in) { if (-1 == rule.in.indexOf(v)) { this.error({ filed: k, key: 'in', value: v, rule: rule.in }); } } if (rule.boolean) { if (typeof data[k] !== 'boolean') { this.error({ filed: k, key: 'boolean', value: v }); } } if (rule.date) { if (!this.isDate(v)) { this.error({ filed: k, key: 'date', value: v }); } else { data[k] = moment(v).toISOString(); } } }// for end return data; } isUrl(v) { return /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(v); } isDate(v) { return moment(v).isValid(); } isInt(v) { return /^\d+$/.test(v); } isFloat(v) { return /^[-+]?(\d+[.])?\d+$/.test(v); } isEmail(v) { return /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(v) } isID(sfzhm_new) { var sum = 0; var weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; var validate = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; for (let m = 0; m < sfzhm_new.length - 1; m++) { sum += sfzhm_new[m] * weight[m]; } let mode = sum % 11; if (sfzhm_new[17] == validate[mode]) { return true; } else { return false; } } /** * Luhn校验算法校验银行卡号 * Description: 银行卡号Luhm校验 * Luhm校验规则:16位银行卡号(19位通用): * 1.将未带校验位的 15(或18)位卡号从右依次编号 1 到 15(18),位于奇数位号上的数字乘以 2。 * 2.将奇位乘积的个十位全部相加,再加上所有偶数位上的数字。 * 3.将加法和加上校验位能被 10 整除。 * 方法步骤很清晰,易理解,需要在页面引用Jquery.js * bankno为银行卡号 */ isCredit(bankno) { var lastNum = bankno.substr(bankno.length - 1, 1);//取出最后一位(与luhm进行比较) var first15Num = bankno.substr(0, bankno.length - 1);//前15或18位 var newArr = new Array(); for (var i = first15Num.length - 1; i > -1; i--) {//前15或18位倒序存进数组 newArr.push(first15Num.substr(i, 1)); } var arrJiShu = new Array(); //奇数位*2的积 <9 var arrJiShu2 = new Array(); //奇数位*2的积 >9 var arrOuShu = new Array(); //偶数位数组 for (var j = 0; j < newArr.length; j++) { if ((j + 1) % 2 == 1) {//奇数位 if (parseInt(newArr[j]) * 2 < 9) arrJiShu.push(parseInt(newArr[j]) * 2); else arrJiShu2.push(parseInt(newArr[j]) * 2); } else //偶数位 arrOuShu.push(newArr[j]); } var jishu_child1 = new Array();//奇数位*2 >9 的分割之后的数组个位数 var jishu_child2 = new Array();//奇数位*2 >9 的分割之后的数组十位数 for (var h = 0; h < arrJiShu2.length; h++) { jishu_child1.push(parseInt(arrJiShu2[h]) % 10); jishu_child2.push(parseInt(arrJiShu2[h]) / 10); } var sumJiShu = 0; //奇数位*2 < 9 的数组之和 var sumOuShu = 0; //偶数位数组之和 var sumJiShuChild1 = 0; //奇数位*2 >9 的分割之后的数组个位数之和 var sumJiShuChild2 = 0; //奇数位*2 >9 的分割之后的数组十位数之和 var sumTotal = 0; for (var m = 0; m < arrJiShu.length; m++) { sumJiShu = sumJiShu + parseInt(arrJiShu[m]); } for (var n = 0; n < arrOuShu.length; n++) { sumOuShu = sumOuShu + parseInt(arrOuShu[n]); } for (var p = 0; p < jishu_child1.length; p++) { sumJiShuChild1 = sumJiShuChild1 + parseInt(jishu_child1[p]); sumJiShuChild2 = sumJiShuChild2 + parseInt(jishu_child2[p]); } //计算总和 sumTotal = parseInt(sumJiShu) + parseInt(sumOuShu) + parseInt(sumJiShuChild1) + parseInt(sumJiShuChild2); //计算Luhm值 var k = parseInt(sumTotal) % 10 == 0 ? 10 : parseInt(sumTotal) % 10; var luhm = 10 - k; var my = false; if (lastNum == luhm) {//Luhm验证通过 my = true; } else {//银行卡号必须符合Luhm校验 my = false; } return my; } isString() { } isChar() { } isFile() { } } //默认required Validator.prototype.messages = { cn: { 'required': '{field}字段不能为空!', 'url': '{field}不是有效的url!', 'email': '{field}不是有效的邮件格式!', 'date': '{value}不是有效的时间格式!', 'int': '{field}必须是整数!', 'float': '{value}不是有效的小数格式!', 'boolean': '{field}必须是布尔类型!', 'in': '{field}的值必须是{value}中的一种!', 'range': '{field}的值TODO:', 'min': '{field}的值最小为{value}!', 'max': '{field}的值最大为{value}!', 'length': '{field}的长度必须TODO:', 'minlength': '{field}的长度最小为{value}!', 'maxlength': '{field}的长度最大为{value}!', 'file': '非法的文件格式!' }, en: {}, fr: {} }; module.exports = Validator;