分享一個javascript validator,請你們拍磚。

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

  1. 不是一個徹底的JSON語法,由於其中包含了JavaScript函數,因此校驗規則是一個Javascript對象。
  2. 規則對象與被校驗數據對象結構基本保持一致,不一致的點在規則對象中包含了描述符

校驗規則

分兩種狀況npm

  1. 描述性校驗,即被校驗的數據節點是否符合描述符的含義,因描述符都是一個對象的key,因此包含描述符的對象,稱爲描述對象
  2. 相等性校驗,若是規則節點key不是描述符,則作相等性比對。

描述符

描述符都是對象的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)

交換等價性,在「向上結合,深度優先」的基本原則下,如下兩個規則rule1rule2描述是等價的,從代碼複雜程度上看,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種類型的描述符,分別是 loadCheckOperatorsloadLogicOperatorsloadHelpOperators。使用姿式以下:

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%左右,基本覆蓋了全部狀況。

202004ll01165407.jpg
202004ll01165407.jpg

篇後語

我對結構化校驗規則的見解:先說優勢,結構化更清晰,這表如今編寫時的思路和閱讀時的理解難度。缺點:受限於結構,有些極端邏輯編寫並不方便且代碼會累贅。

相關文章
相關標籤/搜索