github.com/renjunqing/…javascript
被校验的数据以下:java
var data = {
a: 1
}
复制代码
校验规则a是一个大于0且小于20的整数
,则校验描述以下:git
var rule = {
a: {
$type: 'Number',
$gt: 0, // 大于0
$lt: 20, // 小于20
$factor: 1, // 是1的整数倍
$message: 'a是一个大于0且小于20的整数' // 校验不经过后的报错提示
}
}
复制代码
则校验代码以下:github
import Validator from 'data-police'
const ruleValidator = new Validator(rule)
ruleValidator.check(data).then(d => {
console.log(d)
}).catch(eMsg => {
console.log(eMsg)
})
复制代码
npm install data-police --save
复制代码
ES6
源码,业务项目须要根据本身的环境进行编译。TypeScript
的支持,内含.d.ts
声明文件,使用者无需重复编写。data-police 在语法设计上参考了mongodb的查询语法,恰巧与 JSON Schema又有几分神似。mongodb
描述符
。分两种状况npm
描述对象
。描述符都是对象的key,且以$
开头json
$and
: 须要知足全部规则,如$and: [4, 5, 6]
表示这个节点的值要同时等于 4/5/6(☠️,显然不可能,仅为了介绍)。后端
$or
: 须要知足全部规则,如$or: [4, 5, 6]
表示这个节点的值等于4或等于5或等于6。数组
$if
: 知足条件才作此项校验,如$if: [2, 3]
表示若是这个节点值等于2,则校验它是否等于3(☠️,能感受到你要崩溃)。bash
逻辑运算优先级:“向上结合,深度优先”是基本原则。举例说明:
{
$gt: {
$or: [
{
$or: [3, 4]
},
5
]
}
}
复制代码
如上代码示例:规则表述应是,(大于3或大于4)或大于5
,而非大于((3或4)或5)
。
交换等价性,在“向上结合,深度优先”的基本原则下,如下两个规则rule1
和rule2
描述是等价的,从代码复杂程度上看,rule1
更简单些 。
const rule1 = {
$gt: {
$or: [3, 5]
}
}
const rule2 = {
$or: [
{
$gt: 3,
},
{
$gt: 5
}
]
}
复制代码
$type
: 校验数据类型,使用Object.prototype.toString.call(data).slice(8, -1)
获得的类型值。
$value
: 值等于。
$fn
: 自定义函数。
$gt
: 小于。$gt: 4
,校验值是否小于4。
$gte
: 小于等于。
$lt
: 大于。
$lte
: 大于等于。
$factor
: 因数,能够是任意数字。$factor: 0.1
表示该值是不是0.1的整数倍,可用于校验保留有效位数
。
$isEmail
: true/false。
$isTel
: true/false。
$isUrl
: true/false。
$isID
: true/false,身份证号。
$pattern
: 正则校验字符串。
$len
: 字符串/数组的长度。
$message
: 用户校验未经过后的提示语。
$unique
: 数组元素惟一校验标志,用户数组的每一个元素都是用同样的校验规则。
$proxy
: 代理子节点,用于指定路径校验模式下,由上层节点代理后端节点报错(暂未实现)。
data-police容许用户根据本身的业务特色添加自定义的描述符,Validator
类提供了3个静态方法用来添加以上3种类型的描述符,分别是 loadCheckOperators
、loadLogicOperators
、loadHelpOperators
。使用姿式以下:
import Validator from 'data-police'
Validator.loadCheckOperators({
$isUpper(rule, dataValue) {
return /^\W+$/.test(dataValue)
},
// 与系统描述符重名,将会覆盖系统描述符。同时,自定义描述符也能够覆盖,后来居上。
$gt(rule, dataValue) {
return dataValue < rule
}
})
复制代码
描述符解析器是一个函数,入参如示例中所示,第一个是规则值,第二个是被校验数据值。 在自定义描述符的命名规则上,建议以$
开头,与系统描述符保持一致,但并不会作强制要求。 调用时机,loadxxxxOperators
方法能够重复屡次调用,但针对某一描述符,必须在含有该描述符的规则实例化以前调用,不然会认为这只是一个普通key,而非描述符。
对于结构层级比较深的数据,提供使用路径的方式直达叶子节点,举例:
// 数据
{
a: {
a: {
a: {
a: 1
}
}
}
}
// 正常规则,为了一个叶子节点,嵌套的使人发指
{
a: {
a: {
a: {
a: 1 // 相等性校验,是否等于1
}
}
}
}
// 规则捷径
{
'.a.a.a.a': 1 // 捷径key以.开头,做为捷径的标志,因此要求被校验的数据中key不能够以.开头
}
复制代码
举个表单数据校验的场景,表单通常后多个字段,既要能校验指定字段(填写中),又要可以校验整个表单(提交前),后者无需多言,针对前者提供了指定路径校验的方式。被校验的数据支持两种状况,举例以下:
const rule = {
a: 1,
b: 2
}
const data = {
a: 1,
b: 2
}
// 数据与规则是对应的结构,校验过程是,根据路径找到对应的规则和对应的数据值进行比对。
validator.check(data, '.a', 'root')
复制代码
const rule = {
a: 1,
b: 2
}
const data = 1
// 数据便是在这个路径下的值,校验过程是,根据路径找到规则,与传入的值直接比对。
validator.check(data, '.a', 'branch')
复制代码
规则校验符不只能够用来校验“被校验的数据”,并且能够校验“校验规则”。举例以下:
const rule = {
$len: {
$gt: 4
}
}
复制代码
含义是:字符串的长度小于4
,$gt
被用来校验$len
了。
并非全部的校验规则均可以被校验符校验的,但全部可能被校验的规则均可以被校验,这句话有点拗口。举例说明:
// 含义,大于的数据类型是Number,这句话自己就读不通,因此$gt不能够被$type校验
{
$gt: {
$type: 'Number'
}
}
// 含义,数据类型中要包含Num字符串,前文提到过数据类型中新增了一个特殊类型NumStr,那下边这个规则便可表示,数字和数字字符串。固然,也有其余表示方式。
{
$type: {
$pattern: /Num/
}
}
复制代码
那么,怎么区分哪些校验符能够被校验,哪些不能够呢?除了可能被校验的规则均可以被校验这条感性原则外,还有一条理性原则:能够得出固定值的校验规则均可以被校验,好比5
的数据类型是固定值,那么$type
就能够被校验,而5
大于几就没有固定值,能够大于3能够大于2等等,$gt
不能被校验。在感性原则与理性原则相冲突的状况下,都不会获得指望的校验结果。
约束模式指的是,规则与被校验数据之间的字段对应关系,即数据是否能够比规则多或者少字段,举例以下:
const rule = {
a: 1,
b: 1
}
// 数据比规则少字段
const data1 = {
a: 1
}
// 数据比规则多字段
const data2 = {
a: 1,
b: 1,
c: 1
}
复制代码
默认状况下,多或少字段,都会被忽略,即只校验相互匹配的字段,而经过校验。若是你的业务场景对这方面有特殊要求,能够经过传入check
方法的第二个参数来设置。more: false
会报错非法字段路径
,less: false
会根据规则设置的$message
信息报错。
rule.check(data, {
more: false,
less: false
})
复制代码
单元测试覆盖率90%
左右,基本覆盖了全部状况。
我对结构化校验规则的见解:先说优势,结构化更清晰,这表如今编写时的思路和阅读时的理解难度。缺点:受限于结构,有些极端逻辑编写并不方便且代码会累赘。