check-data
Advanced tools
Comparing version 4.1.0 to 4.1.1
@@ -34,2 +34,4 @@ ## 版本更新 | ||
* 验证表达式中支持赋值全等表达式 | ||
* 新增严格模式Check.strict()方法 | ||
@@ -36,0 +38,0 @@ |
337
index.js
"use strict" | ||
let filterNull = require('filter-null') | ||
let Types = require('./lib/type') | ||
let symbols = require('./lib/symbol') | ||
let common = require('./lib/common') | ||
let Types = require('./type') | ||
let symbols = require('./symbol') | ||
class Parser { | ||
@@ -53,217 +53,253 @@ | ||
// 选项值为验证表达式 | ||
if (options.type) { | ||
return this.Object(data, options, key) | ||
// 优先使用别名 | ||
let field = options.name || key | ||
} | ||
// 空值处理 | ||
if (this.isNull(data, options.ignore)) { | ||
// 选项值为数据类型(值为构造函数或字符串,字符串表示自定义类型) | ||
else if (Types[options]) { | ||
// 默认值 | ||
if (options.default) { | ||
data = options.default | ||
} | ||
if (this.isNull(data)) { | ||
// 严格模式下,禁止空值 | ||
if (this.mode === 'strict') { | ||
return { error: "值不允许为空" } | ||
} | ||
return {} | ||
} | ||
// 禁止空值 | ||
else if (options.allowNull === false) { | ||
return { error: `值不允许为空` } | ||
} | ||
let { error, data: subData } = Types[options].type({ data }) | ||
// 允许空值 | ||
else if (options.allowNull === true) { | ||
return {} | ||
} | ||
if (error) { | ||
return { error: `值${error}` } | ||
} else { | ||
return { data: subData } | ||
} | ||
// 严格模式下,禁止空值 | ||
else if (this.mode === 'strict') { | ||
return { error: `值不允许为空` } | ||
} | ||
} | ||
else { | ||
return {} | ||
} | ||
// 选项值为严格匹配的精确值类型 | ||
else if (data === options) { | ||
} | ||
return { data } | ||
let checks = Types[options.type] | ||
} | ||
// type为内置数据类型 | ||
if (checks) { | ||
// 精确值匹配失败 | ||
else { | ||
for (let name in options) { | ||
let check = checks[name] | ||
if (check) { | ||
let option = options[name] | ||
let { error, data: subData } = check({ data, option, origin: this.origin }) | ||
if (error) { | ||
return { | ||
error: `${error}` | ||
} | ||
} | ||
data = subData | ||
} | ||
} | ||
return { error: `值必须为${options}` } | ||
return { data } | ||
} | ||
} | ||
} | ||
// 不支持的数据类型 | ||
else { | ||
return { | ||
error: `${field}参数配置错误,不支持${options.type}类型` | ||
} | ||
} | ||
/** | ||
* 验证表达式 | ||
* @param {*} data | ||
* @param {*} options | ||
* @param {*} key | ||
*/ | ||
expression(data, options, key) { | ||
// 优先使用别名 | ||
let field = options.name || key | ||
// 空值处理 | ||
if (this.isNull(data, options.ignore)) { | ||
// 默认值 | ||
if (options.default) { | ||
data = options.default | ||
} | ||
// 选项值为数组结构 | ||
else if (Array.isArray(options)) { | ||
// 禁止空值 | ||
else if (options.allowNull === false) { | ||
return { error: `值不允许为空` } | ||
} | ||
if (!Array.isArray(data)) { | ||
// 宽松模式下,跳过空值 | ||
if (this.mode === 'loose') { | ||
if (this.isNull(data)) return {} | ||
} | ||
return { | ||
error: `${key}必须为数组类型` | ||
} | ||
// 允许空值 | ||
else if (options.allowNull === true) { | ||
return {} | ||
} | ||
} | ||
// 严格模式下,禁止空值 | ||
else if (this.mode === 'strict') { | ||
return { error: `值不允许为空` } | ||
} | ||
let dataArray = [] | ||
let itemKey = 0 | ||
else { | ||
return {} | ||
} | ||
// options为单数时采用通用匹配 | ||
if (options.length === 1) { | ||
} | ||
let [option] = options | ||
let checks = Types[options.type] | ||
for (let itemData of data) { | ||
// type为内置数据类型 | ||
if (checks) { | ||
// 子集递归验证 | ||
let { error, data: subData } = this.recursion(itemData, option, itemKey) | ||
if (error) { | ||
return { | ||
error: `[${itemKey}]${error}` | ||
} | ||
} else { | ||
dataArray.push(subData) | ||
for (let name in options) { | ||
let check = checks[name] | ||
if (check) { | ||
let option = options[name] | ||
let { error, data: subData } = check({ data, option, origin: this.origin }) | ||
if (error) { | ||
return { | ||
error: `${error}` | ||
} | ||
itemKey++ | ||
} | ||
data = subData | ||
} | ||
} | ||
// options为复数时采用精确匹配 | ||
else { | ||
return { data } | ||
for (let option of options) { | ||
} | ||
let itemData = data[itemKey] | ||
// 不支持的数据类型 | ||
else { | ||
return { | ||
error: `${field}参数配置错误,不支持${options.type}类型` | ||
} | ||
} | ||
// 子集递归验证 | ||
let { error, data: subData } = this.recursion(itemData, option, itemKey) | ||
} | ||
if (error) { | ||
return { | ||
error: `[${itemKey}]${error}` | ||
} | ||
} else { | ||
dataArray.push(subData) | ||
} | ||
/** | ||
* 对象结构 | ||
* @param {*} data | ||
* @param {*} options | ||
* @param {*} key | ||
*/ | ||
Object(data, options, key) { | ||
itemKey++ | ||
// 选项值为验证表达式 | ||
if (options.type) { | ||
} | ||
return this.expression(data, options, key) | ||
} | ||
} | ||
return { | ||
data: dataArray | ||
} | ||
// 选项值为数组结构 | ||
else if (Array.isArray(options)) { | ||
} | ||
return this.Array(data, options, key) | ||
// 选项值为对象结构 | ||
else { | ||
} | ||
if (typeof data !== 'object') { | ||
// 宽松模式下,跳过空值 | ||
if (this.mode === 'loose') { | ||
if (this.isNull(data)) return {} | ||
} | ||
return { | ||
error: `值必须为Object类型` | ||
} | ||
// 选项值为对象结构 | ||
else { | ||
if (typeof data !== 'object') { | ||
// 宽松模式下,跳过空值 | ||
if (this.mode === 'loose') { | ||
if (this.isNull(data)) return {} | ||
} | ||
return { | ||
error: `值必须为Object类型` | ||
} | ||
} | ||
let dataObj = {} | ||
let dataObj = {} | ||
for (let subKey in options) { | ||
for (let subKey in options) { | ||
let itemData = data[subKey] | ||
let itemOptions = options[subKey] | ||
let { error, data: subData } = this.recursion(itemData, itemOptions, subKey) | ||
let itemData = data[subKey] | ||
let itemOptions = options[subKey] | ||
let { error, data: subData } = this.recursion(itemData, itemOptions, subKey) | ||
if (error) { | ||
// 非根节点 | ||
if (key) { | ||
return { | ||
error: `.${subKey}${error}` | ||
} | ||
} else { | ||
return { | ||
error: `${subKey}${error}` | ||
} | ||
if (error) { | ||
// 非根节点 | ||
if (key) { | ||
return { | ||
error: `.${subKey}${error}` | ||
} | ||
} else { | ||
dataObj[subKey] = subData | ||
return { | ||
error: `${subKey}${error}` | ||
} | ||
} | ||
} else { | ||
dataObj[subKey] = subData | ||
} | ||
return { data: dataObj } | ||
} | ||
return { data: dataObj } | ||
} | ||
// 选项值为数据类型(值为构造函数或字符串,字符串表示自定义类型) | ||
else if (Types[options]) { | ||
} | ||
if (this.isNull(data)) { | ||
// 严格模式下,禁止空值 | ||
if (this.mode === 'strict') { | ||
return { error: "值不允许为空" } | ||
} | ||
return {} | ||
} | ||
/** | ||
* 数组结构 | ||
* @param {*} data | ||
* @param {*} options | ||
* @param {*} key | ||
*/ | ||
Array(data, options, key) { | ||
let { error, data: subData } = Types[options].type({ data }) | ||
if (error) { | ||
return { error: `值${error}` } | ||
} else { | ||
return { data: subData } | ||
if (!Array.isArray(data)) { | ||
// 宽松模式下,跳过空值 | ||
if (this.mode === 'loose') { | ||
if (this.isNull(data)) return {} | ||
} | ||
return { | ||
error: `${key}必须为数组类型` | ||
} | ||
} | ||
// 选项值为严格匹配的精确值类型 | ||
else if (data === options) { | ||
let dataArray = [] | ||
let itemKey = 0 | ||
return { data } | ||
// options为单数时采用通用匹配 | ||
if (options.length === 1) { | ||
let [option] = options | ||
for (let itemData of data) { | ||
// 子集递归验证 | ||
let { error, data: subData } = this.recursion(itemData, option, itemKey) | ||
if (error) { | ||
return { | ||
error: `[${itemKey}]${error}` | ||
} | ||
} else { | ||
dataArray.push(subData) | ||
} | ||
itemKey++ | ||
} | ||
} | ||
// 精确值匹配失败 | ||
// options为复数时采用精确匹配 | ||
else { | ||
return { error: `值必须为${options}` } | ||
for (let option of options) { | ||
let itemData = data[itemKey] | ||
// 子集递归验证 | ||
let { error, data: subData } = this.recursion(itemData, option, itemKey) | ||
if (error) { | ||
return { | ||
error: `[${itemKey}]${error}` | ||
} | ||
} else { | ||
dataArray.push(subData) | ||
} | ||
itemKey++ | ||
} | ||
} | ||
return { | ||
data: dataArray | ||
} | ||
} | ||
@@ -350,2 +386,3 @@ | ||
Types[symbol] = options | ||
Object.assign(Types[symbol], common) | ||
} | ||
@@ -352,0 +389,0 @@ |
{ | ||
"name": "check-data", | ||
"version": "4.1.0", | ||
"version": "4.1.1", | ||
"description": "JS数据验证、转换递归器", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -0,1 +1,3 @@ | ||
功能强大JS数据模型验证、处理工具 | ||
### Install | ||
@@ -7,8 +9,62 @@ | ||
### 使用方法 | ||
## 示例 | ||
check-data支持常规模式、严格模式、宽松模式,默认使用常规模式。 | ||
```js | ||
let sample = { | ||
"name": "test", | ||
"num": "123456789987", | ||
"ObjectId": "59c8aea808deec3fc8da56b6", | ||
"files": ["abc.js", "null", "edb.js"], | ||
"user": { | ||
"username": "莉莉", | ||
"age": 18, | ||
"address": [ | ||
{ "city": "深圳" }, | ||
{ "city": "北京" } | ||
], | ||
}, | ||
"money": "2" | ||
} | ||
> 引入严格模式和宽松模式的主要目的是为了弥补验证表达式的设计缺陷,在数组、对象结构中使用子表达式时无法声明节点自身是否允许为空值。 | ||
let { mongoId, email } = Check.types | ||
let { error, data } = Check(sample, { | ||
"ObjectId": mongoId, | ||
"name": String, | ||
"email": email, | ||
"num": String, | ||
"files": [String], | ||
"user": { | ||
"username": "莉莉", | ||
"age": Number, | ||
"address": [ | ||
{ "city": String }, | ||
{ "city": "北京" } | ||
], | ||
}, | ||
"money": "2" | ||
}) | ||
``` | ||
## 功能特性 | ||
* 采用全镜像数据模型设计,相比其它数据验证器拥有更好的数据结构表现能力和聚合能力。 | ||
* 支持对象和数组的无限嵌套,只管按你的数据结构去建模就好了,不必担心数据复杂度、层级深度的问题。 | ||
* 可以直接复制你的数据进行快速建模,只需要将值替换为类型后就得到了一个基础的验证模型,甚至有时候连值都不用不替换。 | ||
* check-data不仅仅只是数据验证器,同时还拥有很好的数据处理能力,可以在验证前、后灵活的对数据进行扩展。另外,基于js对象的树状结构使代码看起来高度类聚,大大降低了碎片化率。 | ||
* 拥有足够的容错能力,在验证期间你几乎不需要使用try/catch来捕获异常,返回值中的path错误定位信息可以帮助快速追踪错误来源。 | ||
* 当内置数据类型无法满足需求时,可以通过check.use()方法扩展自定义的数据类型。 | ||
## 验证模式 | ||
check-data支持常规、严格、宽松三种验证模式,多数情况下只需要使用常规模式即可。 | ||
引入严格模式和宽松模式的主要原因是为了弥补js对象结构自身的表达分歧,在数组、对象结构中包含子表达式时没有额外的结构来定义空值。 | ||
#### 常规模式 | ||
@@ -180,10 +236,2 @@ | ||
} | ||
}, | ||
in({ data, option: arr }) { | ||
let result = arr.indexOf(data) | ||
if (result === -1) { | ||
return { error: `值必须为${arr}中的一个` } | ||
} else { | ||
return { data } | ||
} | ||
} | ||
@@ -262,3 +310,3 @@ }) | ||
let { error, data } = Check(sample, { | ||
a: [{ "type": String }], | ||
a: [String], | ||
b: [{ | ||
@@ -265,0 +313,0 @@ "type": Number, |
@@ -14,2 +14,17 @@ "use strict" | ||
}, | ||
max({ data, option: max }) { | ||
if (data > max) { | ||
return { error: `不能大于${max}` } | ||
} else { | ||
return { data } | ||
} | ||
}, | ||
in({ data, option: arr }) { | ||
let result = arr.indexOf(data) | ||
if (result === -1) { | ||
return { error: `值必须为${arr}中的一个` } | ||
} else { | ||
return { data } | ||
} | ||
} | ||
}) | ||
@@ -29,11 +44,6 @@ | ||
"18955535547", | ||
"13055655547", | ||
"18655655512", | ||
"15055655512" | ||
], | ||
"mobileArr2": [ | ||
"13055656647", | ||
"18655655512", | ||
"15055699512", | ||
"15855155547" | ||
"18655655512" | ||
], | ||
@@ -49,3 +59,6 @@ } | ||
"type": int, | ||
"allowNull": false | ||
"allowNull": false, | ||
set(value) { | ||
return value * 2 | ||
} | ||
}, | ||
@@ -58,11 +71,12 @@ "email": { | ||
}, | ||
"mobileArr": [mobilePhone], | ||
"mobileArr2": [ | ||
"mobileArr": [ | ||
mobilePhone, | ||
"18655655512", | ||
mobilePhone, | ||
{ | ||
type: mobilePhone, | ||
"type": mobilePhone, | ||
"allowNull": false | ||
} | ||
], | ||
"mobileArr2": [ | ||
mobilePhone, | ||
"18655655512" | ||
] | ||
@@ -73,4 +87,11 @@ }) | ||
t.deepEqual(sample, data, error); | ||
t.deepEqual({ | ||
id: '5687862c08d67e29cd000001', | ||
age: 56, | ||
email: 'erer@gmail.com', | ||
mobile: '15855555547', | ||
mobileArr: ['15855155547', '18955535547'], | ||
mobileArr2: ['13055656647', '18655655512'] | ||
}, data, error); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
50039
21
1351
593