# js-param-checker

> for js param check

Latest version **1.1.9** (published 2019-08-17) · ISC license · 0 weekly downloads

## Install

```sh
npm install js-param-checker
pnpm add js-param-checker
yarn add js-param-checker
bun add js-param-checker
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.1.9 |
| Published | 2019-08-17 |
| First published | 2019-05-12 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 52.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | zhen_zhen_zhang@163.com |
| Maintainers | generzhang |
| Keywords | param, check, param-check, js-param-checker |

## Links

- npm: https://www.npmjs.com/package/js-param-checker
- npm.io page: https://npm.io/package/js-param-checker

## Recent versions

- 1.1.9 (latest) — 2019-08-17
- 1.1.8 — 2019-05-13
- 1.1.6 — 2019-05-13
- 1.1.5 — 2019-05-13
- 1.1.4 — 2019-05-13
- 1.1.3 — 2019-05-13
- 1.1.2 — 2019-05-13
- 1.1.1 — 2019-05-13
- 1.0.1 — 2019-05-13
- 1.0.0 — 2019-05-12

## README

# 参数校验组件

## 前言
如果我们每个接口的开头都充斥着上十行参数校逻辑验的代码，想必这一定是一份非常不友好的代码。  
而本组件的产生，就是为了解决这类问题，使用本组件，可以屏蔽大部分关于参数校验的逻辑，让接口的代码更加专注于处理业务逻辑，同时也能提高代码的可读性。

## 安装方式

> $ npm install js-param-checker

## 快速上手
#### 为了让读者更快了解本组件，我们举一个简单的例子来说明如何使用本组件

读者可以拷贝代码到本地运行看效果

```javascript
const paramChecker = require('js-param-checker'); // 引入本组件

const checkInfo = { // 将参数的校验放到一个配置对象里面
    "productName": "require string(0,)", // 必填，且为字符串，字符串长度大于0
    "productPrice": "require int(0,)", // 必填，且为整数，整数大于0
    "productCount": "require uintz", // 必填，且为非负整数
    "productFrom": "require enums(中国,美国,加拿大)" // 必填，且必须是中国、美国、加拿大其中之一
};

const doBusiness = (dataInfo) => { // 假定这个方法用于处理业务逻辑
    // 按照通常情况下，我们可能会在前面这里对每个参数进行校验
    // 使用本组件，我们只需要短短的几行代码，甚至可以把它提取到公共是外部框架中去做处理
    const error = paramChecker.check(dataInfo, checkInfo); 
    //如果校验格式不正确，error为一个错误对象，error.msg为错误文本提示，否则为null
    if(error){
        throw new Error(error.msg);
    }
    console.log('dataInfo check ok !');
    // 业务逻辑
}

const dataInfo = {
    productName: "苹果",
    productPrice: 5000,
    productCount: 1,
    productFrom: "英国" // 这里会通不过，因为不在枚举的三个值中
};

doBusiness(dataInfo); // 这里我们调用该方法执行业务逻辑
```
上面的例子中，我们把参数校验通过调用 paramChecker.check 来处理，在实际项目中，我们可以把 checkInfo 写成一个配置文件，所有的校验文件统一放到专门的目录下统一管理，甚至连校验那一步都可以进一步封装，即业务方法里面不需要出现任何参数校验的代码，并且参数校验又是可配置的。

## 功能概览
+ 内置多种常见的格式校验类型
+ 支持必填和非必填
+ 支持校验任何复杂的json对象格式数据
+ 支持用户添加自定义校验格式
+ 支持用户修改默认的校验名称
+ 支持用户重写默认的校验格式
+ 支持对校验的格式进行扩展
+ 支持异步方式校验
+ 支持错误提示参数命名

## 功能详解
#### 组件内置支持的校验格式如下

string ～字符串(可设置长度)  
enums ～枚举  
variable ～js变量  
letter ～字母  
upletter ～大写字母  
lowletter ～小写字母  
timestamp ～时间戳  
time ～时间  
date ～日期  
datetime ～日期时间  
email ～邮件  
phone ~手机号码  
ip ~IP地址  
url ~url链接  
postcode ~邮编号码  
idcard ~身份证号  
notchinese ~非中文  
chinese ~中文  
bool ~布尔  
int ~整数(可设置取值范围)  
uint ~正整数(可设置取值范围)    
uintz ~自然数(可设置取值范围)    
float ~浮点数  
ufloat ~正浮点数  
array ~数组  
uarray ~非空数组  
object ~对象  
uobject ~非空对象 

#### 支持参数的必填和非必填校验
组件通过关键字 _require_ 和 _optional_ 来声明参数是否必填，如

```javascript
{
    "createDate": "require date", //创建时间必填
    "remark": "optional string" //备注可不填
}
```
上面例子中，createDate参数是必填的，且约定为date格式，如果检验结果为没值或格式不对，就会提示
"createDate必填，且为YYYY-MM-DD的日期格式"，而remark参数如果没值则不会有错误提示

#### 组件支持对任意复杂的json格式对象进行校验
有时候我们的参数并不是形如  
```javascript
{
    product: "apple", 
    count: 120
}   
```
这种简单的对象，而是各种数组和对象嵌套，如 
```javascript
{
    product: {
        name:"apple", 
        sale: {
            byMonth: [20, 10, 11, 12, 20, ...],  //数组每一项表示每个月的销售额
            bySaleman: { //每个销售员的销售额
                lilei: 20,
                lily: 30,
                ...
            }
        },
        ...
    }
}
```
而本组件就是针对这种场景，可支持对数组内的参数进行校验，甚至可以精确到校验数组的某一项，或者是更深层次的值校验（文章后面会有例子）。

#### 支持用户添加自定义校验格式
有时候用户需要有自己的一些自定义校验规则，本组件支持用户添加自己的校验规则，方式如下：

```javascript
paramChecker.setting({
    add: {
        myrule: (name, value) => {
            if(typeof value !== 'object'){
                return `${name}不符合自定义校验规则`;
            }else{
                return null;
            }
        }
    }
});
```
在使用的时候，就可以通过如
```javascript
{
    "createDate": "require date", // 创建时间必填
    "remark": "optional string", // 备注可不填
    "moreInfo": "require myrule" // 组件会调用上面设置的自定义规则来校验
}
```
如果我们传入的参数值如下
```javascript
{
    "createDate": "2019-05-10", 
    "remark": "测试", 
    "moreInfo": "test"
}
```
那么校验结果会是 "moreInfo不符合自定义校验规则"，上面完整的例子如下：
```javascript
const paramChecker = require('js-param-checker');
paramChecker.setting({
    add: {
        myrule: (name, value) => {
            if(typeof value !== 'object'){
                return `${name}不符合自定义校验规则`;
            }else{
                return null;
            }
        }
    }
});
const error = paramChecker.check(
    {
       "createDate": "2019-05-10", 
       "remark": "测试", 
       "moreInfo": "test"
   }, 
   {
      "createDate": "require date", // 创建时间必填
      "remark": "optional string", // 备注可不填
      "moreInfo": "require myrule" // 组件会调用上面设置的自定义规则来校验
   }
);

console.log(`校验结果：${error?error.msg:'ok'}`); // 校验结果：moreInfo不符合自定义校验规则
```
上面如果要校验通过，moreInfo需要是一个json对象，如
```javascript
{
    "createDate": "2019-05-10", 
    "remark": "测试", 
    "moreInfo": {
        "color": "red",
        "price": 100
    }
}
```
此时会输出 "校验结果：ok"
#### 支持用户修改默认的校验名称
这个功能是为了能让用户可以修改本组件内置的格式名称，比如你可以把内置规则名"date"改名为"DATE"，"string"改为"str"，那么上面的例子中，需要修改如下
```javascript
paramChecker.setting({ //说明：paramChecker.setting是可以多次调用的，每次调用的结果会叠加
    rename: {
        string: 'str'
    }
});
```
```javascript
{
   "createDate": "require date", // 创建时间必填
   "remark": "optional str", // 备注可不填
   "moreInfo": "require myrule" // 组件会调用上面设置的自定义规则来校验
}
```


#### 支持用户重写默认的校验格式
有时候内置的校验格式并不适应实际的应用场景，比如内置的date的校验格式是YYYY-MM-DD，而实际是需要YYYY/MM/DD的格式，那么可以重写内置的校验格式，方式如下：
```javascript
paramChecker.setting({
    override: {
        date: (name, value) => {
            const reg = /^(\d{4})\/(\d{2})\/(\d{2})$/;
            const matchs = value.match(reg);
            if(matchs === null || matchs.length === 0){
                return `${name}必须为YYYY/MM/DD格式，当前值：${value}`;;
            }
            return null;

        }
    }
});
```
#### 支持对校验的格式进行扩展
上面的myrule自定义格式中，如果传入的不是json对象，会提示不符合自定义格式。而如果传入的是对象，则能校验通过。如果希望对这个规则进行扩展，比如校验对象的属性个数，那么可以使用如下方式扩展  
```javascript
paramChecker.setting({
    add: {
        myrule: (name, value, extra) => {//这里多出来的extra参数，就是用于扩展规则校验的，后面会说明如何传入这个参数
            if(typeof value !== 'object'){ //这里有点不严谨，数组也是对象，但是作为例子，大家知道意思就行
                return `${name}不符合自定义校验规则`;
            }else{
                if(Object.keys(value).length !== parseInt(extra)){
                    return `${name}不符合自定义校验规则`;
                }else{
                    return null;
                }
            }
        }
    }
});
```
接下来我们来约定，moreInfo必须是一个拥有三个属性的对象
```javascript
const error = paramChecker.check(
    {
       "createDate": "2019-05-10", 
       "remark": "测试", 
       "moreInfo": {
           "color": "red",
           "price": 100
       }
   }, 
   {
      "createDate": "require date", // 创建时间必填
      "remark": "optional string", // 备注可不填
      "moreInfo": "require myrule(3)" // 这里通过在myrule后面加上小括号，小括号里面的值就是传入自定义规则的实现方法的extra参数
   }
);
console.log(error); //这里会打印出一个错误对象 {"msg":"moreInfo不符合自定义校验规则", "param":"moreInfo", "check":"require myrule(3)", "value":{"color":"red","price":100}}
```

#### 支持异步方式校验
有时候参数是否符合要求需要调用后台接口去判断，比如有时候我们拿到的城市参数在db中是动态变化的，此时就需要异步去db获取这个动态的枚举值，本组件可通过异步的方式来校验参数值。  
异步校验同样支持新增校验规则和重写原规则，新增规则的例子如下
```javascript
const paramChecker = require('js-param-checker');

//fetchData模拟去后台获取城市的枚举值
const fetchData = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(['深圳', '广州', '上海'])
        }, 100);
    });
}

paramChecker.setting({
    add: {
        myrule: async (name, value) => { // 这里需要使用到async声明这是一个异步方法
            const data = await fetchData();
            if(data.indexOf(value)>=0){ // 判断value是否属于后台返回的数据中的一个
                return null;
            }else{
                return `${name}不符合自定义校验规则`;
            }
        }
    }
});
//接下来在使用方面也会稍有不同，异步方式需要调用 checkAsync 方法
paramChecker.checkAsync({
       "createDate": "2019-05-10", 
       "remark": "测试", 
       "moreInfo": "北京"
    }, 
    {
       "createDate": "require date", // 创建时间必填
       "remark": "optional string", // 备注可不填
       "moreInfo": "require myrule" // 这里会去后台db拉去数据校验
    }
).then((error) => {
    console.log(`校验结果：${error?error.msg:'ok'}`);
});
```
#### 支持错误提示参数命名
有时候我们希望给到用户的是中文或者更加通熟易懂的名称，上面的例子中，
```javascript
"createDate": "require date", // 创建时间必填
```
如果 createDate 格式错误
```javascript
"createDate": "20190510", 
```
那么提示会如下   
createDate必须为YYYY-MM-DD格式，当前值：20190510   
我们可以设置如下
```javascript
"createDate 产品创建时间": "require date", // 创建时间必填
```
那么提示会变成： "产品创建时间必须为YYYY-MM-DD格式，当前值：20190510"  
以上这种提示方式是不是就变得更加友好呢？
另外，我们重命名的参数在规则方法中可以通过name参数取到，如 
```javascript
myrule: (name, value) => { // 这里的name就会变成 产品创建时间
    
}
```

## 复杂示例

// 下面直接模拟一个比较复杂的场景，假设我们需要校验一个userInfo对象的格式，这个对象嵌套了复杂的数据结构
// 读者可以把以下的例子拷贝到本地测试，修改字段的值，看看校验的提示

```javascript

const paramChecker = require('js-param-checker');

const userInfo = {
    name: 'zzz',
    age: 18,
    sex: 'male',
    nation: '汉',
    description: '一枚好青年',
    birthday: '2020-01-01',
    contact: [
        13888888888,
        'zhen_zhen_zhang@163.com',
        {
            qq: ['88888', '999999']
        },
        {
            wechat: 'iloveyou'
        }
    ],
    company: {
        name: 'tencent',
        city: '深圳',
        homepage: 'https://www.tencent.com',
        groups: [
            {
                groupName: 'WXG',
                staffCount: 1,
            },
            {
                groupName: 'IEG',
                staffCount: 2,
            },
            {
                groupName: 'CDG',
                staffCount: 3,
            }
        ],
        products: [
            {
                productName: 'qq',
                productInfo: {
                    userCount: 4,
                    publishTime: '2019-01-01'
                },
            },
            {
                productName: 'wechat',
                productInfo: {
                    userCount: 5,
                    publishTime: '2020-01-01'
                },
            }
        ]
    }
};

const checkInfo = {
    "name": "require string(0,)",  // 名称长度必须大于0
    "age": "require uint",  // 年龄必须大于0
    "sex": "require enums(female,male)", // 性别必须为female和male其中之一
    "nation 民族": "require chinese", // 民族必须为汉字
    "description": "require string(0,)", // 个人描述长度必须大于0
    "birthday": "require date", // 生日格式必须为YYYY-MM-DD

    "contact": "require uarray", // 联系方式是个非空数组
    "contact[0]": "require phone", // 联系方式第一项必须为手机号码
    "contact[1]": "require email", // 联系方式第二项必须为邮箱
    "contact[2]": "require uobject", // 联系方式第三项必须为非空objecj对象
    "contact[2].qq": "require array", // 联系方式第三项的属性包含qq，且qq对应的值是数组（数组可为空）
    "contact[2].qq[]": "require string(4,)", // 联系方式qq的位数长度必须大于4
    "contact[3]": "require uobject", // 联系方式第四项必须为非空boject对象
    "contact[3].wechat": "require string(0,)", // 联系方式第四项的属性必须包含wechat，且wechat的长度必须大于0

    "company": "require uobject", // 公司必须是非空的object对象
    "company.name": "require string(0,)", // 公司名称长度必须大于0
    "company.city": "require enums(深圳,广州,北京,上海)", // 公司城市只能是 “深圳,广州,北京,上海” 中的一个
    "company.homepage": 'require url', // 公司主页
    "company.groups": "require uarray", // 公司的事业群是一个非空数组
    "company.groups[]": "require uobject", // 每个事业群是一个非空对象
    "company.groups[].groupName": "require upletter", // 事业群名称必须是大写字母组成
    "company.groups[].staffCount": "require uint", //事业群人数必须是正整数
    "company.products": "require uarray", // 公司生产的产品是一个非空数组
    "company.products[]": "require uobject", // 每个产品是一个非空对象
    "company.products[].productName": "require string(0,)", // 产品名称长度必须大于0
    "company.products[].productInfo": "require uobject", // 产品详情是一个非空对象
    "company.products[].productInfo.userCount": "require uint", // 产品详情的用户数必须是正整数
    "company.products[].productInfo.publishTime": "require date" // 产品详情的发布时间必须是YYYY-MM-DD格式
};

const error = paramChecker.check(userInfo, checkInfo);

console.log(`result: ${error?error.msg:'ok'}`);

```


## 其他依赖
无

---
_Source: https://npm.io/package/js-param-checker · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
