first version
This commit is contained in:
commit
6a3a851c31
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
*.swp
|
47
index.js
Normal file
47
index.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
const types = require('./types/index.js')
|
||||||
|
const BaseType = require('./types/base.js') // eslint-disable-line
|
||||||
|
const validator = {}
|
||||||
|
module.exports = validator
|
||||||
|
|
||||||
|
validator.Base = types.Base
|
||||||
|
validator.string = () => new types.StringType()
|
||||||
|
validator.number = () => new types.NumberType()
|
||||||
|
validator.boolean = () => new types.BooleanType()
|
||||||
|
validator.array = () => new types.ArrayType()
|
||||||
|
validator.object = () => new types.ObjectType()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @exports
|
||||||
|
* @typedef SchemaField
|
||||||
|
* @property {BaseType} type
|
||||||
|
* @property {SchemaField} children
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @exports
|
||||||
|
* @typedef {Object<string, SchemaField|BaseType>} Schema
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate
|
||||||
|
* @param {Object} src
|
||||||
|
* @param {Schema} schema
|
||||||
|
*/
|
||||||
|
validator.validate = function (src, schema) {
|
||||||
|
if (typeof src !== 'object' || typeof schema !== 'object') throw new Error('source or schema not object')
|
||||||
|
|
||||||
|
for (const it in schema) {
|
||||||
|
if (schema[it] instanceof BaseType) {
|
||||||
|
const result = schema[it].validate(src[it])
|
||||||
|
if (result) throw new Error(`field [${it}]: ${result}`)
|
||||||
|
} else if (typeof schema[it] === 'object' && 'type' in schema[it] && schema[it].type instanceof BaseType) {
|
||||||
|
const result = schema[it].type.validate(src[it])
|
||||||
|
if (result) throw new Error(`field [${it}]: ${result}`)
|
||||||
|
} else {
|
||||||
|
throw new Error('not get any check schema type')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof schema[it] === 'object' && 'children' in schema[it]) {
|
||||||
|
validator.validate(src[it], schema[it].children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4649
package-lock.json
generated
Normal file
4649
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
15
package.json
Normal file
15
package.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "mtfos-validator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"jest": "^26.0.1"
|
||||||
|
}
|
||||||
|
}
|
56
types/array.js
Normal file
56
types/array.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
const Base = require('./base.js')
|
||||||
|
const util = require('util')
|
||||||
|
|
||||||
|
class TypeArray extends Base {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
this._type = 'object'
|
||||||
|
this._empty = false
|
||||||
|
this._min = null
|
||||||
|
this._max = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set allow empty
|
||||||
|
*/
|
||||||
|
empty () {
|
||||||
|
this._empty = true
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set min length
|
||||||
|
* @param {number} num
|
||||||
|
*/
|
||||||
|
min (num) {
|
||||||
|
if (!isFinite(num) || num === true || num === false) throw new Error('input wrong')
|
||||||
|
if (this._max !== null && this._max <= num) throw new Error(`num >= ${this._max}`)
|
||||||
|
if (num < 0) throw new Error('array length must >= 0')
|
||||||
|
this._min = parseFloat(num)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set max length
|
||||||
|
* @param {number} num
|
||||||
|
*/
|
||||||
|
max (num) {
|
||||||
|
if (!isFinite(num) || num === true || num === false) throw new Error('input wrong')
|
||||||
|
if (this._min !== null && this._min >= num) throw new Error(`num <= ${this._min}`)
|
||||||
|
this._max = parseFloat(num)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
validate (value) {
|
||||||
|
if (value === undefined && this._required) return `required`
|
||||||
|
if (value === undefined) return null
|
||||||
|
/* eslint-disable-next-line */
|
||||||
|
if (typeof value !== this._type) return `${util.inspect(value, false, null)} type not array`
|
||||||
|
if (!Array.isArray(value)) return `${util.inspect(value, false, null)} type not array`
|
||||||
|
if (!this._empty && value.length === 0) return `not allow empty`
|
||||||
|
if (this._min !== null && value.length < this._min) return `value length < ${this._min}`
|
||||||
|
if (this._max !== null && value.length > this._max) return `value length > ${this._max}`
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = TypeArray
|
62
types/array.test.js
Normal file
62
types/array.test.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/* eslint-disable no-undef */
|
||||||
|
const TypeArray = require('./array.js')
|
||||||
|
|
||||||
|
describe('test validate schema type array', () => {
|
||||||
|
function throwFunc (val) {
|
||||||
|
return () => {
|
||||||
|
if (val) throw new Error(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it('test type array check array', async () => {
|
||||||
|
const arr = new TypeArray()
|
||||||
|
|
||||||
|
expect(throwFunc(arr.validate({}))).toThrow()
|
||||||
|
expect(throwFunc(arr.validate(false))).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test type array with required', async () => {
|
||||||
|
const arr = new TypeArray().required()
|
||||||
|
|
||||||
|
arr.validate([1, 2])
|
||||||
|
|
||||||
|
expect(throwFunc(arr.validate(undefined))).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test type array with empty', async () => {
|
||||||
|
const arr = new TypeArray().empty()
|
||||||
|
|
||||||
|
arr.validate([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test type array without empty', async () => {
|
||||||
|
const arr = new TypeArray()
|
||||||
|
|
||||||
|
expect(throwFunc(arr.validate([]))).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test type array with min length', async () => {
|
||||||
|
const arr = new TypeArray().min(2)
|
||||||
|
|
||||||
|
expect(() => new TypeArray().min()).toThrow()
|
||||||
|
expect(() => new TypeArray().min(false)).toThrow()
|
||||||
|
expect(() => new TypeArray().min(-1)).toThrow()
|
||||||
|
expect(() => new TypeArray().max(1).min(2)).toThrow()
|
||||||
|
|
||||||
|
arr.validate([1, 2])
|
||||||
|
|
||||||
|
expect(throwFunc(arr.validate([1]))).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test type array with max length', async () => {
|
||||||
|
const arr = new TypeArray().max(2)
|
||||||
|
|
||||||
|
expect(() => new TypeArray().max()).toThrow()
|
||||||
|
expect(() => new TypeArray().max(false)).toThrow()
|
||||||
|
expect(() => new TypeArray().min(5).max(3)).toThrow()
|
||||||
|
|
||||||
|
arr.validate([1])
|
||||||
|
|
||||||
|
expect(throwFunc(arr.validate([1, 2, 3]))).toThrow()
|
||||||
|
})
|
||||||
|
})
|
27
types/base.js
Normal file
27
types/base.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* type builder interface
|
||||||
|
*
|
||||||
|
* @interface
|
||||||
|
*/
|
||||||
|
class BaseType {
|
||||||
|
constructor () {
|
||||||
|
this._type = 'base'
|
||||||
|
this._required = false
|
||||||
|
}
|
||||||
|
|
||||||
|
required () {
|
||||||
|
this._required = true
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate data
|
||||||
|
* @param {any} value
|
||||||
|
* @return {string?}
|
||||||
|
*/
|
||||||
|
validate (value) {
|
||||||
|
throw new Error('not impl')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BaseType
|
19
types/boolean.js
Normal file
19
types/boolean.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const Base = require('./base.js')
|
||||||
|
const util = require('util')
|
||||||
|
|
||||||
|
class TypeBoolean extends Base {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
this._type = 'boolean'
|
||||||
|
}
|
||||||
|
|
||||||
|
validate (value) {
|
||||||
|
if (value === undefined && this._required) return `required`
|
||||||
|
if (value === undefined) return null
|
||||||
|
/* eslint-disable-next-line */
|
||||||
|
if (typeof value !== this._type) return `${util.inspect(value, false, null)} type not ${this._type}`
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TypeBoolean
|
19
types/boolean.test.js
Normal file
19
types/boolean.test.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/* eslint-disable no-undef */
|
||||||
|
const TypeBoolean = require('./boolean.js')
|
||||||
|
|
||||||
|
describe('test validate schema type boolean', () => {
|
||||||
|
function throwFunc (val) {
|
||||||
|
return () => {
|
||||||
|
if (val) throw new Error(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it('test type boolean required', async () => {
|
||||||
|
const bool = new TypeBoolean().required()
|
||||||
|
|
||||||
|
bool.validate(true)
|
||||||
|
|
||||||
|
expect(throwFunc(bool.validate(undefined))).toThrow()
|
||||||
|
expect(throwFunc(bool.validate({}))).toThrow()
|
||||||
|
})
|
||||||
|
})
|
15
types/index.js
Normal file
15
types/index.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const Base = require('./base.js')
|
||||||
|
const StringType = require('./string.js')
|
||||||
|
const NumberType = require('./number.js')
|
||||||
|
const BooleanType = require('./boolean.js')
|
||||||
|
const ObjectType = require('./object.js')
|
||||||
|
const ArrayType = require('./array.js')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Base,
|
||||||
|
StringType,
|
||||||
|
NumberType,
|
||||||
|
BooleanType,
|
||||||
|
ObjectType,
|
||||||
|
ArrayType
|
||||||
|
}
|
46
types/number.js
Normal file
46
types/number.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
const Base = require('./base.js')
|
||||||
|
const util = require('util')
|
||||||
|
|
||||||
|
class TypeNumber extends Base {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
this._type = 'number'
|
||||||
|
this._min = null
|
||||||
|
this._max = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set min value
|
||||||
|
* @param {number} num
|
||||||
|
*/
|
||||||
|
min (num) {
|
||||||
|
if (!isFinite(num) || num === true || num === false) throw new Error('input wrong')
|
||||||
|
if (this._max !== null && this._max <= num) throw new Error(`num >= ${this._max}`)
|
||||||
|
this._min = parseFloat(num)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set max value
|
||||||
|
* @param {number} num
|
||||||
|
*/
|
||||||
|
max (num) {
|
||||||
|
if (!isFinite(num) || num === true || num === false) throw new Error('input wrong')
|
||||||
|
if (this._min !== null && this._min >= num) throw new Error(`num <= ${this._min}`)
|
||||||
|
this._max = parseFloat(num)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
validate (value) {
|
||||||
|
if (value === undefined && this._required) return `required`
|
||||||
|
if (value === undefined) return null
|
||||||
|
/* eslint-disable-next-line */
|
||||||
|
if (typeof value !== this._type) return `${util.inspect(value, false, null)} type not ${this._type}`
|
||||||
|
const v = parseFloat(value)
|
||||||
|
if (this._min !== null && v < this._min) return `value < ${this._min}`
|
||||||
|
if (this._max !== null && v > this._max) return `value > ${this._max}`
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TypeNumber
|
43
types/number.test.js
Normal file
43
types/number.test.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* eslint-disable no-undef */
|
||||||
|
const TypeNumber = require('./number.js')
|
||||||
|
|
||||||
|
describe('test validate schema type number', () => {
|
||||||
|
function throwFunc (val) {
|
||||||
|
return () => {
|
||||||
|
if (val) throw new Error(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it('test type number with required', async () => {
|
||||||
|
const num = new TypeNumber().required()
|
||||||
|
|
||||||
|
num.validate(1)
|
||||||
|
|
||||||
|
expect(throwFunc(num.validate(undefined))).toThrow()
|
||||||
|
expect(throwFunc(num.validate({}))).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test type number with min', async () => {
|
||||||
|
const num = new TypeNumber().required().min(1)
|
||||||
|
|
||||||
|
expect(() => new TypeNumber().min()).toThrow()
|
||||||
|
expect(() => new TypeNumber().min(false)).toThrow()
|
||||||
|
expect(() => new TypeNumber().max(1).min(2)).toThrow()
|
||||||
|
|
||||||
|
num.validate(2)
|
||||||
|
|
||||||
|
expect(throwFunc(num.validate(-1))).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test type number with max', async () => {
|
||||||
|
const num = new TypeNumber().required().max(2)
|
||||||
|
|
||||||
|
expect(() => new TypeNumber().max()).toThrow()
|
||||||
|
expect(() => new TypeNumber().max(false)).toThrow()
|
||||||
|
expect(() => new TypeNumber().min(3).max(2)).toThrow()
|
||||||
|
|
||||||
|
num.validate(2)
|
||||||
|
|
||||||
|
expect(throwFunc(num.validate(3))).toThrow()
|
||||||
|
})
|
||||||
|
})
|
18
types/object.js
Normal file
18
types/object.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
const Base = require('./base.js')
|
||||||
|
const util = require('util')
|
||||||
|
|
||||||
|
class TypeObject extends Base {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
this._type = 'object'
|
||||||
|
}
|
||||||
|
|
||||||
|
validate (value) {
|
||||||
|
if (value === undefined && this._required) return `required`
|
||||||
|
if (value === undefined) return null
|
||||||
|
/* eslint-disable-next-line */
|
||||||
|
if (typeof value !== this._type) return `${util.inspect(value, false, null)} type not ${this._type}`
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = TypeObject
|
19
types/object.test.js
Normal file
19
types/object.test.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/* eslint-disable no-undef */
|
||||||
|
const TypeObject = require('./object.js')
|
||||||
|
|
||||||
|
describe('test validate type schema object', () => {
|
||||||
|
function throwFunc (val) {
|
||||||
|
return () => {
|
||||||
|
if (val) throw new Error(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it('test object type with required', async () => {
|
||||||
|
const obj = new TypeObject().required()
|
||||||
|
|
||||||
|
obj.validate({})
|
||||||
|
|
||||||
|
expect(throwFunc(obj.validate(undefined))).toThrow()
|
||||||
|
expect(throwFunc(obj.validate(false))).toThrow()
|
||||||
|
})
|
||||||
|
})
|
59
types/string.js
Normal file
59
types/string.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const Base = require('./base.js')
|
||||||
|
const util = require('util')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @implements {Base}
|
||||||
|
*/
|
||||||
|
class TypeString extends Base {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
this._type = 'string'
|
||||||
|
this._max = null
|
||||||
|
this._min = null
|
||||||
|
this._empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set min length
|
||||||
|
* @param {number} num
|
||||||
|
*/
|
||||||
|
min (num) {
|
||||||
|
if (!isFinite(num) || num === true || num === false) throw new Error('input wrong')
|
||||||
|
if (this._max !== null && this._max <= num) throw new Error(`num >= ${this._max}`)
|
||||||
|
this._min = parseFloat(num)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set max length
|
||||||
|
* @param {number} num
|
||||||
|
*/
|
||||||
|
max (num) {
|
||||||
|
if (!isFinite(num) || num === true || num === false) throw new Error('input wrong')
|
||||||
|
if (this._min !== null && this._min >= num) throw new Error(`num <= ${this._min}`)
|
||||||
|
this._max = parseFloat(num)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set allow empty
|
||||||
|
*/
|
||||||
|
empty () {
|
||||||
|
this._empty = true
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
validate (value) {
|
||||||
|
if (value === undefined && this._required) return `required`
|
||||||
|
if (value === undefined) return null
|
||||||
|
/* eslint-disable-next-line */
|
||||||
|
if (typeof value !== this._type) return `${util.inspect(value, false, null)} type not ${this._type}`
|
||||||
|
if (!this._empty && !value) return `value empty`
|
||||||
|
const len = value.length
|
||||||
|
if (this._min !== null && len < this._min) return `value length < ${this._min}`
|
||||||
|
if (this._max !== null && len > this._max) return `value length > ${this._max}`
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TypeString
|
58
types/string.test.js
Normal file
58
types/string.test.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* eslint-disable no-undef */
|
||||||
|
const TypeString = require('./string.js')
|
||||||
|
|
||||||
|
describe('test validate type schema string', () => {
|
||||||
|
function throwFunc (val) {
|
||||||
|
return () => {
|
||||||
|
if (val) throw new Error(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it('test string type without required', async () => {
|
||||||
|
const str = new TypeString()
|
||||||
|
str.validate(undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test string type with required', async () => {
|
||||||
|
const str = new TypeString().required()
|
||||||
|
str.validate('123')
|
||||||
|
|
||||||
|
expect(throwFunc(str.validate(undefined))).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test string type with empty', async () => {
|
||||||
|
const str = new TypeString().empty().required()
|
||||||
|
str.validate('')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test string type without empty', async () => {
|
||||||
|
const str = new TypeString().required()
|
||||||
|
str.validate('asd')
|
||||||
|
|
||||||
|
expect(throwFunc(str.validate(''))).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test string type with min length', async () => {
|
||||||
|
const str = new TypeString().required().min(2)
|
||||||
|
|
||||||
|
expect(() => new TypeString().min()).toThrow()
|
||||||
|
expect(() => new TypeString().min(false)).toThrow()
|
||||||
|
expect(() => new TypeString().max(2).min(3)).toThrow()
|
||||||
|
|
||||||
|
str.validate('asd')
|
||||||
|
|
||||||
|
expect(throwFunc(str.validate('a'))).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('test string type with max length', async () => {
|
||||||
|
const str = new TypeString().required().max(2)
|
||||||
|
|
||||||
|
expect(() => new TypeString().max()).toThrow()
|
||||||
|
expect(() => new TypeString().max(false)).toThrow()
|
||||||
|
expect(() => new TypeString().min(2).max(1)).toThrow()
|
||||||
|
|
||||||
|
str.validate('a')
|
||||||
|
|
||||||
|
expect(throwFunc(str.validate('asd'))).toThrow()
|
||||||
|
})
|
||||||
|
})
|
26
validator.test.js
Normal file
26
validator.test.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/* eslint-disable no-undef */
|
||||||
|
const validator = require('./index.js')
|
||||||
|
|
||||||
|
describe('test validator validate', () => {
|
||||||
|
test('validate test 1', () => {
|
||||||
|
const data = {
|
||||||
|
field: 'string'
|
||||||
|
}
|
||||||
|
const schema = {
|
||||||
|
field: validator.string().required()
|
||||||
|
}
|
||||||
|
|
||||||
|
validator.validate(data, schema)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('validate test 2', () => {
|
||||||
|
const data = {
|
||||||
|
wrong: 1
|
||||||
|
}
|
||||||
|
const schema = {
|
||||||
|
wrong: validator.string().required()
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(() => validator.validate(data, schema)).toThrow()
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user