diff --git a/example.js b/example.js index 54cadbd..351e5d8 100644 --- a/example.js +++ b/example.js @@ -2,7 +2,7 @@ var Parameter = require('./'); var rule = { name: 'string', - age: {type: 'int', max: 200}, + age: {type: 'int', max: 200, message: { max: '年龄不能大于 200 岁' }}, gender: ['male', 'female'], working: 'boolean', salary: {type: 'number', min: 0}, @@ -15,7 +15,7 @@ var rule = { required: false, rule: { name: 'string', - age: 'int', + age: { type: 'int', message: { required: '子女年龄不能为空' }}, gender: ['male', 'female'], birthday: {type: 'date', required: false} } diff --git a/index.js b/index.js index e1db09a..470b692 100644 --- a/index.js +++ b/index.js @@ -44,6 +44,10 @@ class Parameter { } } + message(rule, key, defaultMessage) { + return rule.message && rule.message[key] || defaultMessage; + } + /** * validate * @@ -89,7 +93,7 @@ class Parameter { if (!has) { if (rule.required !== false) { errors.push({ - message: this.t('required'), + message: this.message(rule, 'required', this.t('required')), field: key, code: this.t('missing_field') }); @@ -254,6 +258,13 @@ function formatRule(rule) { rule.required = false; } + rule.message = rule.message || {} + if (typeof rule.message === 'string') { + rule.message = { + [rule.type]: rule.message, + } + } + return rule; } @@ -317,15 +328,15 @@ function convert(rule, obj, key, defaultConvert) { function checkInt(rule, value) { if (typeof value !== 'number' || value % 1 !== 0) { - return this.t('should be an integer'); + return this.message(rule, 'int', this.t('should be an integer')); } if (rule.hasOwnProperty('max') && value > rule.max) { - return this.t('should smaller than %s', rule.max); + return this.message(rule, 'max', this.t('should smaller than %s', rule.max)); } if (rule.hasOwnProperty('min') && value < rule.min) { - return this.t('should bigger than %s', rule.min); + return this.message(rule, 'min', this.t('should bigger than %s', rule.min)); } } @@ -344,13 +355,13 @@ function checkInt(rule, value) { function checkNumber(rule, value) { if (typeof value !== 'number' || isNaN(value)) { - return this.t('should be a number'); + return this.message(rule, 'number', this.t('should be a number')); } if (rule.hasOwnProperty('max') && value > rule.max) { - return this.t('should smaller than %s', rule.max); + return this.message(rule, 'max', this.t('should smaller than %s', rule.max)); } if (rule.hasOwnProperty('min') && value < rule.min) { - return this.t('should bigger than %s', rule.min); + return this.message(rule, 'min', this.t('should bigger than %s', rule.min)); } } @@ -372,7 +383,7 @@ function checkNumber(rule, value) { function checkString(rule, value) { if (typeof value !== 'string') { - return this.t('should be a string'); + return this.message(rule, rule.type || 'string', this.t('should be a string')); } // if required === false, set allowEmpty to true by default @@ -386,18 +397,18 @@ function checkString(rule, value) { if (!value) { if (allowEmpty) return; - return this.t('should not be empty'); + return this.message(rule, 'allowEmpty', '') || this.message(rule, 'empty', '') || this.t('should not be empty'); } if (rule.hasOwnProperty('max') && value.length > rule.max) { - return this.t('length should smaller than %s', rule.max); + return this.message(rule, 'max', this.t('length should smaller than %s', rule.max)); } if (rule.hasOwnProperty('min') && value.length < rule.min) { - return this.t('length should bigger than %s', rule.min); + return this.message(rule, 'min', this.t('length should bigger than %s', rule.min)); } if (rule.format && !rule.format.test(value)) { - return rule.message || this.t('should match %s', rule.format); + return this.message(rule, 'format', this.t('should match %s', rule.format)); } } @@ -412,7 +423,10 @@ function checkString(rule, value) { */ function checkId(rule, value) { - return checkString.call(this, { format: ID_RE, allowEmpty: rule.allowEmpty }, value); + const errorMessage = checkString.call(this, { format: ID_RE, allowEmpty: rule.allowEmpty }, value); + if (errorMessage) { + return this.message(rule, 'id', errorMessage); + } } /** @@ -426,7 +440,10 @@ function checkId(rule, value) { */ function checkDate(rule, value) { - return checkString.call(this, { format: DATE_TYPE_RE, allowEmpty: rule.allowEmpty }, value); + const errorMessage = checkString.call(this, { format: DATE_TYPE_RE, allowEmpty: rule.allowEmpty }, value); + if (errorMessage) { + return this.message(rule, 'date', errorMessage); + } } /** @@ -440,7 +457,10 @@ function checkDate(rule, value) { */ function checkDateTime(rule, value) { - return checkString.call(this, { format: DATETIME_TYPE_RE, allowEmpty: rule.allowEmpty }, value); + const errorMessage = checkString.call(this, { format: DATETIME_TYPE_RE, allowEmpty: rule.allowEmpty }, value); + if (errorMessage) { + return this.message(rule, 'dateTime', errorMessage); + } } /** @@ -454,7 +474,7 @@ function checkDateTime(rule, value) { function checkBoolean(rule, value) { if (typeof value !== 'boolean') { - return this.t('should be a boolean'); + return this.message(rule, 'bool', '') || this.message(rule, 'boolean', '') || this.t('should be a boolean'); } } @@ -475,7 +495,7 @@ function checkEnum(rule, value) { throw new TypeError('check enum need array type values'); } if (rule.values.indexOf(value) === -1) { - return this.t('should be one of %s', rule.values.join(', ')); + return this.message(rule, 'enum', this.t('should be one of %s', rule.values.join(', '))); } } @@ -489,11 +509,13 @@ function checkEnum(rule, value) { */ function checkEmail(rule, value) { - return checkString.call(this, { + const errorMessage = checkString.call(this, { format: EMAIL_RE, - message: rule.message || this.t('should be an email'), allowEmpty: rule.allowEmpty, }, value); + if (errorMessage) { + return this.message(rule, 'email', this.t('should be an email')); + } } /** @@ -513,10 +535,10 @@ function checkPassword(rule, value, obj) { rule.format = PASSWORD_RE; var error = checkString.call(this, rule, value); if (error) { - return error; + return this.message(rule, 'password', error); } if (rule.compare && obj[rule.compare] !== value) { - return this.t('should equal to %s', rule.compare); + return this.message(rule, 'compare', this.t('should equal to %s', rule.compare)); } } @@ -530,11 +552,13 @@ function checkPassword(rule, value, obj) { */ function checkUrl(rule, value) { - return checkString.call(this, { + const error = checkString.call(this, { format: URL_RE, - message: rule.message || this.t('should be a url'), allowEmpty: rule.allowEmpty }, value); + if (error) { + return this.message(rule, 'url', this.t('should be a url')); + } } /** @@ -551,7 +575,7 @@ function checkUrl(rule, value) { function checkObject(rule, value) { if (typeof value !== 'object') { - return this.t('should be an object'); + return this.message(rule, 'object', this.t('should be an object')); } if (rule.rule) { @@ -583,14 +607,14 @@ function checkObject(rule, value) { function checkArray(rule, value) { if (!Array.isArray(value)) { - return this.t('should be an array'); + return this.message(rule, 'array', this.t('should be an array')); } if (rule.hasOwnProperty('max') && value.length > rule.max) { - return this.t('length should smaller than %s', rule.max); + return this.message(rule, 'max', this.t('length should smaller than %s', rule.max)); } if (rule.hasOwnProperty('min') && value.length < rule.min) { - return this.t('length should bigger than %s', rule.min); + return this.message(rule, 'min', this.t('length should bigger than %s', rule.min)); } if (!rule.itemType) { diff --git a/test/index.test.js b/test/index.test.js index 1df1948..1ff7a7c 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -127,6 +127,26 @@ describe('parameter', () => { var rule = { int: {type: 'int', max: 100, min: 0 }}; parameter.validate(rule, value)[0].message.should.equal('should bigger than 0'); }); + + it('should check error with custom message', () => { + var value = { int: '1' }; + var rule = { int: {type: 'int', message: 'custom message'}}; + var rule2 = { int: {type: 'int', message: { int: 'custom message'}}}; + parameter.validate(rule, value)[0].message.should.equal('custom message'); + parameter.validate(rule2, value)[0].message.should.equal('custom message'); + }); + + it('should check error with custom min message', () => { + var value = { int: 1 }; + var rule = { int: {type: 'int', min: 2, message: { min: '不能小于2' }}}; + parameter.validate(rule, value)[0].message.should.equal('不能小于2'); + }); + + it('should check error with custom max message', () => { + var value = { int: 10 }; + var rule = { int: {type: 'int', max: 5, message: { max: '不能大于5' }}}; + parameter.validate(rule, value)[0].message.should.equal('不能大于5'); + }); }); describe('number', () => { @@ -160,6 +180,26 @@ describe('parameter', () => { var rule = { number: {type: 'number', max: 100, min: 0 }}; parameter.validate(rule, value)[0].message.should.equal('should bigger than 0'); }); + + it('should check error with custom message', () => { + var value = { number: '-1' }; + var rule = { number: {type: 'number', message: 'custom message'}}; + var rule2 = { number: {type: 'number', message: { number: 'custom message'}}}; + parameter.validate(rule, value)[0].message.should.equal('custom message'); + parameter.validate(rule2, value)[0].message.should.equal('custom message'); + }); + + it('should check error with custom min message', () => { + var value = { number: 1 }; + var rule = { number: {type: 'number', min: 2, message: { min: '不能小于2' }}}; + parameter.validate(rule, value)[0].message.should.equal('不能小于2'); + }); + + it('should check error with custom max message', () => { + var value = { number: 10 }; + var rule = { number: {type: 'number', max: 5, message: { max: '不能大于5' }}}; + parameter.validate(rule, value)[0].message.should.equal('不能大于5'); + }); }); describe('string', () => { @@ -177,6 +217,10 @@ describe('parameter', () => { parameter.validate(rule, value)[0].message.should.equal('should not be empty'); rule = { string: {type: 'string', empty: false }}; parameter.validate(rule, value)[0].message.should.equal('should not be empty'); + rule = { string: {type: 'string', empty: false, message: { empty: '不能为空' } }}; + parameter.validate(rule, value)[0].message.should.equal('不能为空'); + rule = { string: {type: 'string', empty: false, message: { allowEmpty: '不能为空' } }}; + parameter.validate(rule, value)[0].message.should.equal('不能为空'); }); it('should check with rule.trim', () => { @@ -188,18 +232,24 @@ describe('parameter', () => { var value = { string: 'hello' }; var rule = { string: {type: 'string', max: 4, min: 1 }}; parameter.validate(rule, value)[0].message.should.equal('length should smaller than 4'); + rule = { string: {type: 'string', max: 4, min: 1, message: { max: '不能多于4个字符'} }}; + parameter.validate(rule, value)[0].message.should.equal('不能多于4个字符'); }); it('should check min error', () => { var value = { string: 'hello' }; var rule = { string: {type: 'string', max: 100, min: 10 }}; parameter.validate(rule, value)[0].message.should.equal('length should bigger than 10'); + rule = { string: {type: 'string', max: 100, min: 10, message: { min: '不能少于10个字符'} }}; + parameter.validate(rule, value)[0].message.should.equal('不能少于10个字符'); }); it('should check format error', () => { var value = {string: 'hello'}; - var rule = {string: /\d+/}; + var rule = {string: { type: 'string', format: /\d+/ }}; parameter.validate(rule, value)[0].message.should.equal('should match /\\d+/'); + rule = {string: { type: 'string', format: /\d+/, message: { format: '格式不正确' }}}; + parameter.validate(rule, value)[0].message.should.equal('格式不正确'); }); it('should check allowEmpty with format ok', () => { @@ -241,6 +291,8 @@ describe('parameter', () => { var value = {id : '0524x' }; var rule = {id: 'id'}; parameter.validate(rule, value)[0].message.should.equal('should match /^\\d+$/'); + rule = {id: { type: 'id', message: 'ID 格式不正确' }}; + parameter.validate(rule, value)[0].message.should.equal('ID 格式不正确'); }); }); @@ -256,6 +308,8 @@ describe('parameter', () => { var value = {date : '2014-xx-xx' }; var rule = {date: 'date'}; parameter.validate(rule, value)[0].message.should.equal('should match /^\\d{4}\\-\\d{2}\\-\\d{2}$/'); + rule = {date: { type: 'date', message: '日期格式不正确'}}; + parameter.validate(rule, value)[0].message.should.equal('日期格式不正确'); }); it('should check allowEmpty ok', () => { @@ -279,6 +333,8 @@ describe('parameter', () => { var value = {dateTime : '2014-11-11 00:xx:00' }; var rule = {dateTime: 'dateTime'}; parameter.validate(rule, value)[0].message.should.equal('should match /^\\d{4}\\-\\d{2}\\-\\d{2} \\d{2}:\\d{2}:\\d{2}$/'); + rule = {dateTime: { type: 'dateTime', message: "时间格式不正确" }}; + parameter.validate(rule, value)[0].message.should.equal('时间格式不正确'); }); it('should datetime alias to dateTime', () => { @@ -310,6 +366,10 @@ describe('parameter', () => { var value = {boolean : '2014-11-11 00:xx:00' }; var rule = {boolean: 'boolean'}; parameter.validate(rule, value)[0].message.should.equal('should be a boolean'); + rule = {boolean: { type: 'boolean', message: '应该是一个布尔值' }}; + parameter.validate(rule, value)[0].message.should.equal('应该是一个布尔值'); + rule = {boolean: { type: 'bool', message: '应该是一个布尔值' }}; + parameter.validate(rule, value)[0].message.should.equal('应该是一个布尔值'); }); }); @@ -332,6 +392,8 @@ describe('parameter', () => { var value = {enum : 4 }; var rule = {enum: [1, 2, 3]}; parameter.validate(rule, value)[0].message.should.equal('should be one of 1, 2, 3'); + rule = {enum: { type: 'enum', values: [1, 2, 3], message: '不合法的枚举值' }}; + parameter.validate(rule, value)[0].message.should.equal('不合法的枚举值'); }); }); @@ -423,6 +485,25 @@ describe('parameter', () => { } ]); + parameter.validate({ + password: { + type: 'password', + compare: 're-password', + message: { + compare: '两次输入的密码不一致' + } + } + }, { + password: '123123', + 're-password': '1231231', + }).should.eql([ + { + code: 'invalid', + field: 'password', + message: '两次输入的密码不一致' + } + ]); + parameter.validate({ password: { type: 'password',