anyvalidation

0.0.4 • Public • Published

anyvalidation

一个可重用、可扩展的模型校验模块

features

  • 校验函数可扩展,可以自己定义符合ValidatorFn接口的校验函数
  • 校验函数高度重用,一个复杂的校验逻辑可由基本校验函数组合而成
  • 与数据模型解耦,支持任意数据模型
  • 校验配置可序列化,即支持从后端传入校验逻辑

install

npm install anyvalidation

quick start

var V = require('anyvalidation');    
var AnyValidation = V.AnyValidation;
var dvfs = V.defaultValidatorFns;
var propertyResolver = V.propertyResolvers.propertyResolver;
var prefix = dvfs.prefix;
var some = dvfs.some;
var isInteger = dvfs.isInteger;
var largeEqualThan = dvfs.largeEqualThan;
var lessEqualThan = dvfs.lessEqualThan;

var bizData = {
  "user": {
     "age": "not a number",
     "name": "hello kitty"
    },
  "count": null
};
var validatorInfo = [
 {
    "resolvePath": ["count"],
    "validatorFn": prefix("数量", some(required(), isInteger()))
  },
  {
    "resolvePath": ["user", "age"],
    "validatorFn": prefix("年龄", some(required(), isInteger()))
  }
];
var anyVali = new AnyValidation(validatorInfo, propertyResolver);
console.log(anyVali.validateAll(bizData));
console.log(anyVali.validateOne(["user", "age"], "not a number"));

ValidatorFn

ValidatorFn 是最基本的校验函数,它必须满足如下接口:

ValidatorFn :: param -> data -> errMsg

其中,param生成校验函数的参数; data表示被校验的数据; errMsg表示返回的错误信息,如果没有错则返回undefined

V.defaultValidatorFns提供了一些常用ValidatorFn var V = require('anyvalidation');
var dvfs = V.defaultValidatorFns;

比如,可以从defaultValidatorFns中获取小于等于的校验函数如下:

var lessEqualThan = dvfs.lessEqualThan;

var lessEqualThan = function(num) {
    return function (data) {
        if (data > num) {
           return "必须小于等于" + num;
        }
   }
}

可以看到,lessEqualThan本身并不能直接用作校验函数,只有将num传入后,才会制造出一个小于等于num的函数。

过程抽象也是ValidatorFn

经常,一个字段的校验是有很多简单约束组合而成。 比如,我们要校验某个输入是数字,且范围为[1, 9999999999]。 这里可以将整个约束拆解为:

  1. 数字
  2. 大于等于1
  3. 小于等于9999999999
  4. 过程:某一个校验函数验证失败,则直接结束返回errMsg, 否则下一个校验函数

其中,第4个过程约束也抽象为ValidatorFn,即some

Some :: [ValidatorFn] -> data -> errMsg 不同的是,它的第一个入参param为各校验函数。

有时,我们的errMsg需要一些修饰,比如说“单次购买下限小于1...”,即在原本的校验结果中再加入点主语。 于是,就可用过程prefix,它也是ValidatorFn

prefix :: ("some subject" -> ValidatorFn) -> data -> errMsg

以上的复杂校验可以写成如下方式:

var prefix = dvfs.prefix;
var some = dvfs.some;
var isInteger = dvfs.isInteger;
var largeEqualThan = dvfs.largeEqualThan;
var lessEqualThan = dvfs.lessEqualThan;
var validator = prefix("单次购买下限", some(isInteger(), largeEqualThan(1), 
lessEqualThan(9999999999)));
console.log(validator("not a number"));
console.log(validator(-1));
console.log(validator(10000000000000000));

=>

    单次购买下限必须是数字
    单次购买下限必须大于等于1
    单次购买下限必须小于等于9999999999

模型校验

经常,我们需要校验一个页面的业务数据。业务数据本质上一棵树。

var bizData = {
  "user": {
     "age": "not a number",
     "name": "hello kitty"
    },
  "count": null
};

bizData树上的每个节点都有可能被加上约束。 在不同的操作场景下,有时需要校验某个节点,有时需要全量校验。 于是,我们把所有需要校验的节点打平,组成一个校验信息的数组validatorInfo。 通过AnyValidation,可以实现模型校验

AnyValidation

参数名 描述 说明
validatorInfo 打平的校验配置信息 是一个数组。每个节点由resolvePath和校验信息组成
propertyResolver 从bizData中获取被校验值的函数 入参是resolvePath,系统已经提供propertyResolver(针对普通js对象),immuPropertyResolver(immutablejs)均挂在 V.propertyResolvers下,也可根据不同的状态管理方案做定制化
opts 可选选项 fromConfig: vailidatorInfo是否为json方式, extendValidatorFns: 扩展ValidatorFn
var V = require('anyvalidation');    
var AnyValidation = V.AnyValidation;
var propertyResolver = V.propertyResolvers.propertyResolver;

var validatorInfo = [
 {
    "resolvePath": ["count"],
    "validatorFn": prefix("数量", some(required(), isInteger()))
  },
  {
    "resolvePath": ["user", "age"],
    "validatorFn": prefix("年龄", some(required(), isInteger()))
  }
];
var anyVali = new AnyValidation(validatorInfo, propertyResolver);
console.log(anyVali.validateAll(bizData));
console.log(anyVali.validateOne(["user", "age"], "not a number"));

=>

[ { key: 'count', errMsg: '数量必填' },
  { key: 'user_age', errMsg: '年龄必须是数字' } ]
年龄必须是数字

校验配置化

有时,校验逻辑需要从后端传给前端,我们只需把AnyValidation的fromConfig设置为true,并调整validatorInfo

var V = require('anyvalidation');    
var AnyValidation = V.AnyValidation;
var propertyResolver = V.propertyResolvers.propertyResolver;
var extendValidatorFns = {
    "whateverWrong": function() {
        return function(data) {
            return "WRONG!!";
        }
    }   
}
var validatorInfo2 = [
{
    "resolvePath": ["count"],
    "validatorConfig": {
        "type": "function",
        "name": "prefix",
        "params": [
            {
                "type": "data",
                "value": "数量"
            },
            {
                "type": "function",
                "name": "some",
                "params": [
                
                {
                        "type": "function",
                        "name": "whateverWrong",
                        "params": []
                    },
                    {
                        "type": "function",
                        "name": "required",
                        "params": []
                    },
                    {
                        "type": "function",
                        "name": "isInteger",
                        "params": []
                    }
                ]
            }
        ]
    }
},
{
    "resolvePath": ["user", "age"],
    "validatorConfig": {
        "type": "function",
        "name": "prefix",
        "params": [
            {
                "type": "data",
                "value": "年龄"
            },
            {
                "type": "function",
                "name": "some",
                "params": [
                    {
                        "type": "function",
                        "name": "required",
                        "params": []
                    },
                    {
                        "type": "function",
                        "name": "isInteger",
                        "params": []
                    }
                ]
            }
        ]
    }
}
];
var anyValidation = new AnyValidation(validatorInfo2, propertyResolver, {fromConfig: true, extendValidatorFns: extendValidatorFns})
console.log(anyValidation.validateAll(bizData));
console.log(anyValidation.validateOne(["user", "age"], "jajajajajaja"))

=>

[ { key: 'count', errMsg: '数量WRONG!!' },
  { key: 'user_age', errMsg: '年龄必须是数字' } ]
年龄必须是数字

Versions

Current Tags

  • Version
    Downloads (Last 7 Days)
    • Tag
  • 0.0.4
    0
    • latest

Version History

  • Version
    Downloads (Last 7 Days)
    • Published
  • 0.0.4
    0
  • 0.0.3
    1
  • 0.0.2
    1
  • 0.0.1
    1

Package Sidebar

Install

npm i anyvalidation

Weekly Downloads

3

Version

0.0.4

License

ISC

Last publish

Collaborators

  • heynoodles