diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..d174481 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '35 4 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..d8222a0 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,18 @@ +name: CI + +on: + push: + branches: [ master ] + + pull_request: + branches: [ master ] + + workflow_dispatch: {} + +jobs: + Job: + name: Node.js + uses: artusjs/github-actions/.github/workflows/node-test.yml@v1 + with: + os: 'ubuntu-latest' + version: '10, 12, 14, 16, 18' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1612587 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,17 @@ +name: Release + +on: + push: + branches: [ master ] + + workflow_dispatch: {} + +jobs: + release: + name: Node.js + uses: artusjs/github-actions/.github/workflows/node-release.yml@v1 + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GIT_TOKEN: ${{ secrets.GIT_TOKEN }} + with: + checkTest: false diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b927ff9..0000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -sudo: false -language: node_js -notifications: - email: false -node_js: - - '10' - - '8' - - '6' - - '4' -install: - - npm i npminstall && npminstall -script: - - npm run ci -after_script: - - npminstall codecov && codecov -after_success: - - npm run semantic-release -branches: - except: - - /^v\d+\.\d+\.\d+$/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8ab5e14 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +## [3.7.0](https://github.com/node-modules/parameter/compare/v3.6.0...v3.7.0) (2023-03-14) + + +### Features + +* custom error message ([#68](https://github.com/node-modules/parameter/issues/68)) ([818cd23](https://github.com/node-modules/parameter/commit/818cd23b2c6dd0470939b03218e8746feed4f467)), closes [#31](https://github.com/node-modules/parameter/issues/31) [#15](https://github.com/node-modules/parameter/issues/15) diff --git a/LICENSE.txt b/LICENSE.txt index 2964e35..f12ec4a 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ This software is licensed under the MIT License. -Copyright(c) 2013 - 2018 node-modules and other contributors. +Copyright(c) 2013 - present node-modules and other contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 014e357..4e304a3 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,12 @@ parameter ======= [![NPM version][npm-image]][npm-url] -[![build status][travis-image]][travis-url] +[![Node.js CI](https://github.com/node-modules/parameter/actions/workflows/nodejs.yml/badge.svg)](https://github.com/node-modules/parameter/actions/workflows/nodejs.yml) [![Test coverage][codecov-image]][codecov-url] [![npm download][download-image]][download-url] -[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release) [npm-image]: https://img.shields.io/npm/v/parameter.svg?style=flat-square [npm-url]: https://npmjs.org/package/parameter -[travis-image]: https://img.shields.io/travis/node-modules/parameter.svg?style=flat-square -[travis-url]: https://travis-ci.org/node-modules/parameter [codecov-image]: https://codecov.io/github/node-modules/parameter/coverage.svg?branch=master [codecov-url]: https://codecov.io/github/node-modules/parameter?branch=master [download-image]: https://img.shields.io/npm/dm/parameter.svg?style=flat-square @@ -34,7 +31,7 @@ $ npm install parameter --save - `options.translate` - translate function - `options.validateRoot` - config whether to validate the passed in value must be a object, default to `false`. - `options.convert` - convert primitive params to specific type, default to `false`. - - `optinos.widelyUndefined` - convert empty string(`''`), NaN, Null to undefined, this option can make `rule.required` more powerful, default to `false`.__This may change the original input params__. + - `options.widelyUndefined` - convert empty string(`''`), NaN, Null to undefined, this option can make `rule.required` more powerful, default to `false`.__This may change the original input params__. - `validate(rule, value)` - validate the `value` conforms to `rule`. return an array of errors if break rule. - `addRule(type, check)` - add custom rules. - `type` - rule type, required and must be string type. @@ -195,8 +192,8 @@ If type is `array`, there has four addition rule: - `itemType` - The type of every item in this array. - `rule` - An object that validate the items of the array. Only work with `itemType`. -- `max` - The maximun length of the array. -- `min` - The minimun lenght of the array. +- `max` - The maximum length of the array. +- `min` - The minimum lenght of the array. #### abbr @@ -240,13 +237,18 @@ If type is `array`, there has four addition rule: } ``` -### Release process +## License -We're using [semantic-release](https://github.com/semantic-release/semantic-release) to run npm publish -after every commit on master. +[MIT](LICENSE.txt) -See [Default Commit Message Format](https://github.com/semantic-release/semantic-release#default-commit-message-format) for details. + -## License +## Contributors -[MIT](LICENSE.txt) +|[
fengmk2](https://github.com/fengmk2)
|[
dead-horse](https://github.com/dead-horse)
|[
huacnlee](https://github.com/huacnlee)
|[
hotoo](https://github.com/hotoo)
|[
sang4lv](https://github.com/sang4lv)
|[
ghostoy](https://github.com/ghostoy)
| +| :---: | :---: | :---: | :---: | :---: | :---: | +[
beliefgp](https://github.com/beliefgp)
|[
taylorharwin](https://github.com/taylorharwin)
|[
tomowang](https://github.com/tomowang)
|[
hdumok](https://github.com/hdumok)
|[
paranoidjk](https://github.com/paranoidjk)
|[
zcxsythenew](https://github.com/zcxsythenew)
+ +This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Tue Apr 05 2022 10:44:22 GMT+0800`. + + 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/package.json b/package.json index b6b5fec..4d6ed94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parameter", - "version": "3.6.0", + "version": "3.7.0", "description": "A parameter verify tools.", "main": "index.js", "module": "index.es5.js", @@ -9,21 +9,19 @@ "index.es5.js" ], "scripts": { - "test": "mocha -R spec -t 1000 test/*.test.js", - "cov": "istanbul cover _mocha -- -t 1000 test/*.test.js", + "lint": "echo 'ignore'", + "test": "egg-bin test", + "cov": "egg-bin cov", "ci": "npm run cov", "build:es5": "babel index.js --presets babel-preset-es2015 -o index.es5.js", - "prepublish": "npm run build:es5", - "semantic-release": "semantic-release pre && npm publish && semantic-release post" + "prepublish": "npm run build:es5" }, "devDependencies": { "babel-cli": "^6.26.0", "babel-preset-es2015": "^6.24.1", "beautify-benchmark": "0", "benchmark": "*", - "istanbul": "*", - "mocha": "^5.2.0", - "semantic-release": "^6.3.6", + "egg-bin": "^4.19.0", "should": "*" }, "repository": { @@ -36,7 +34,7 @@ "univ" ], "engines": { - "node": ">= 4.0.0" + "node": ">= 10.0.0" }, "author": "fengmk2 ", "license": "MIT" diff --git a/test/index.test.js b/test/index.test.js index 0aa14b4..1ff7a7c 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,5 +1,6 @@ 'use strict'; +var assert = require('assert'); var should = require('should'); var util = require('util'); var Parameter = require('..'); @@ -61,15 +62,17 @@ describe('parameter', () => { describe('validate', () => { it('should throw error when received a non object', () => { - var value = null; - var rule = {int: {type: 'int1', required: false}}; - let err; - try { - parameter.validate(rule, undefined) - } catch (e) { - err = e; - } - should(err.message).equal('Cannot read property \'int\' of undefined'); + var value = null; + var rule = {int: {type: 'int1', required: false}}; + let err; + try { + parameter.validate(rule, undefined) + } catch (e) { + err = e; + } + + assert(err.message === 'Cannot read property \'int\' of undefined' || + err.message === 'Cannot read properties of undefined (reading \'int\')'); }); it('should invalid type throw', () => { @@ -124,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', () => { @@ -157,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', () => { @@ -174,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', () => { @@ -185,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', () => { @@ -238,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 格式不正确'); }); }); @@ -253,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', () => { @@ -276,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', () => { @@ -307,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('应该是一个布尔值'); }); }); @@ -329,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('不合法的枚举值'); }); }); @@ -420,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', @@ -482,10 +566,10 @@ describe('parameter', () => { 'ftp://foo.bar/baz', 'http://foo.bar/?q=Test%20URL-encoded%20stuff', 'http://مثال.إختبار', - 'http://例子.测试' + 'http://例子.测试', ].forEach(function (url) { - should.not.exist(parameter.validate({ name: 'url' }, { name: url })); - should.not.exist(parameter.validate({ name: { type: 'url' } }, { name: url })); + assert(parameter.validate({ name: 'url' }, { name: url }) === undefined); + assert(parameter.validate({ name: { type: 'url' } }, { name: url }) === undefined); }); }); @@ -511,9 +595,16 @@ describe('parameter', () => { 'http://www.foo.bar./', 'http://.www.foo.bar./', 'http://10.1.1.1', - 'http://10.1.1.254' + 'http://10.1.1.254', + // private & local networks will fail + // https://gist.github.com/dperini/729294#file-regex-weburl-js-L77 + // https://github.com/node-modules/parameter/issues/92 + 'http://localhost', + 'http://127.0.0.1', + 'http://127.0.0.1:8080', + 'http://127.0.0.1:80', ].forEach(function (url) { - parameter.validate({ name: 'url' }, { name: url }).should.eql([ + assert.deepStrictEqual(parameter.validate({ name: 'url' }, { name: url }), [ { code: 'invalid', field: 'name', @@ -521,7 +612,7 @@ describe('parameter', () => { } ]); - parameter.validate({ name: { type: 'url', message: '不合法 url' } }, { name: url }).should.eql([ + assert.deepStrictEqual(parameter.validate({ name: { type: 'url', message: '不合法 url' } }, { name: url }), [ { code: 'invalid', field: 'name',