value-validator
Advanced tools
Sorry, the diff of this file is not supported yet
+10
| language: node_js | ||
| node_js: | ||
| # - "0.10" | ||
| # - "0.11" | ||
| # - "4.2" | ||
| # - "5.0" | ||
| # - "5.1" | ||
| # - "5.2" | ||
| # - "5.3" | ||
| - "6" |
+27
| # Test against this version of Node.js | ||
| environment: | ||
| matrix: | ||
| # - nodejs_version: "0.6" # not supported by appveyor | ||
| # - nodejs_version: "0.8" # not supported by appveyor | ||
| # - nodejs_version: "0.10" | ||
| # - nodejs_version: "0.11" | ||
| # - nodejs_version: "4" | ||
| # - nodejs_version: "5" | ||
| - nodejs_version: "6" | ||
| # Install scripts. (runs after repo cloning) | ||
| install: | ||
| # Get the latest stable version of Node.js or io.js | ||
| - ps: Install-Product node $env:nodejs_version | ||
| # install modules | ||
| - npm install | ||
| # Post-install test scripts. | ||
| test_script: | ||
| # Output useful info for debugging. | ||
| - node --version | ||
| - npm --version | ||
| - npm test | ||
| # Don't actually build. | ||
| build: off |
Sorry, the diff of this file is not supported yet
+140
| [](https://travis-ci.org/kaelzhang/value-validator) | ||
| <!-- optional appveyor tst | ||
| [](https://ci.appveyor.com/project/kaelzhang/value-validator) | ||
| --> | ||
| <!-- optional npm version | ||
| [](http://badge.fury.io/js/value-validator) | ||
| --> | ||
| <!-- optional npm downloads | ||
| [](https://www.npmjs.org/package/value-validator) | ||
| --> | ||
| <!-- optional dependency status | ||
| [](https://david-dm.org/kaelzhang/value-validator) | ||
| --> | ||
| # value-validator | ||
| ## Install | ||
| ```sh | ||
| $ npm install value-validator --save | ||
| ``` | ||
| ## Usage | ||
| ```js | ||
| const Validator = require('value-validator') | ||
| const validator = new Validator([ | ||
| /.{4,}/, | ||
| /^[a-z0-9_]+$/i, | ||
| function (v) { | ||
| const done = this.async() | ||
| asyncCheckExists(v, exists => { | ||
| if (exists) { | ||
| return done(new Error(`username "${v}" already exists.`)) | ||
| } | ||
| done(null) | ||
| }) | ||
| } | ||
| ]) | ||
| validator.validate('foo', (err, pass) => { | ||
| err // null | ||
| pass // false, to short | ||
| }) | ||
| validator.validate('foo.bar', (err, pass) => { | ||
| err // null | ||
| pass // false, only letters, numbers and underscores. | ||
| }) | ||
| validator.validate('steve', (err, pass) => { | ||
| err // maybe `new Error('username "steve" already exists.')` | ||
| pass // false | ||
| }) | ||
| validator.validate('cook', (err, pass) => { | ||
| // maybe "cook" is a valid username | ||
| err // null | ||
| pass // true | ||
| }) | ||
| ``` | ||
| ## new Validator(rule, options) | ||
| - **rule** `RegExp|function()|String|Array.<mixed>` rule could be a regular expression, a function, a string (validator preset), or an array of mixed-type of the former three. | ||
| ### Sync Function-type `rule` | ||
| The function should accept only one argument, which is the value to be validated. | ||
| If the function returns a `Boolean`, it indicates whether the validation is passed, and the `err` will be `null` | ||
| ```js | ||
| const validator = new Validator(v => v > 10) | ||
| validator.validate(5, (err, pass) => { | ||
| err // null | ||
| pass // false | ||
| }) | ||
| ``` | ||
| If the function returns an `Error`, it means the validation fails, and the error will passed to the callback function of `validate(v, callback)` as the first parameter `err`. | ||
| ```js | ||
| const validator = new Validator(v => { | ||
| if (v > 10) { | ||
| return true | ||
| } | ||
| return new Error('should larger than 10') | ||
| }) | ||
| validator.validate(5, (err, pass) => { | ||
| err // new Error('should larger than 10') | ||
| pass // false | ||
| }) | ||
| ``` | ||
| ### Async validator | ||
| To define an asynchronous validator, we need to use the common [this.async()](https://www.npmjs.com/package/wrap-as-async) style. | ||
| See the first example. | ||
| ## Validator Presets | ||
| Validator presets are pre-defined abbreviation of a certain validation, or a set of validations. | ||
| ```js | ||
| Validator.registerPresets({ | ||
| // To define a function-typed preset | ||
| unique: function (v) { | ||
| const done = this.async() | ||
| asyncCheckExists(v, exists => { | ||
| if (exists) { | ||
| return done(new Error(`username "${v}" already exists.`)) | ||
| } | ||
| done(null) | ||
| }) | ||
| }, | ||
| min4: /.{4,}/, | ||
| // A preset could be a set of presets. | ||
| username: [ | ||
| 'min4', | ||
| /^[a-z0-9_]+$/i, | ||
| 'unique' | ||
| ] | ||
| }) | ||
| // Then we could use `username` as the test rule. | ||
| const validator = new Validator('username') | ||
| ``` | ||
| ## License | ||
| MIT |
| [{ | ||
| test: RegExp, | ||
| message: String | ||
| }] | ||
| {} |
+194
| 'use strict' | ||
| const make_array = require('make-array') | ||
| const wrap = require('wrap-as-async') | ||
| const async = require('async') | ||
| const util = require('util') | ||
| class Validator { | ||
| constructor (rules, { | ||
| codec = default_codec | ||
| } = {}) { | ||
| this._codec = codec | ||
| this._context = null | ||
| this._rules = [] | ||
| make_array(rules).forEach((rule) => { | ||
| this.add(rule) | ||
| }) | ||
| } | ||
| context (context) { | ||
| this._context = context | ||
| return this | ||
| } | ||
| add (rule) { | ||
| this._add(rule) | ||
| return this | ||
| } | ||
| validate (v, callback) { | ||
| async.everySeries(this._rules, (tester, done) => { | ||
| const isAsync = tester.call( | ||
| this._context, v, | ||
| (err, pass) => { | ||
| err = typeof err === 'string' | ||
| ? new Error(err) | ||
| : err || null | ||
| pass = determine_pass(err, pass) | ||
| done(err, pass) | ||
| } | ||
| ) | ||
| }, (err, pass) => { | ||
| // async.everySeries sets `pass` as `undefined` | ||
| // if there is an error encountered. | ||
| callback(err, determine_pass(err, pass)) | ||
| }) | ||
| } | ||
| // @returns {function()} wrapped | ||
| _add (rule) { | ||
| if (typeof rule === 'string') { | ||
| return this._decodePreset(rule) | ||
| } | ||
| this._rules.push(this._wrapRule(rule)) | ||
| } | ||
| _wrapRule (rule) { | ||
| if (typeof rule === 'function') { | ||
| return wrap(rule) | ||
| } | ||
| if (util.isRegExp(rule)) { | ||
| return wrap((v) => { | ||
| return rule.test(v) | ||
| }) | ||
| } | ||
| const str = rule && rule.toString | ||
| ? rule.toString() | ||
| : '' | ||
| throw new Error(`value-validator: invalid rule "${str}"`) | ||
| } | ||
| _decodePreset (rule) { | ||
| return this._codec(rule) | ||
| .forEach(({name, args}) => { | ||
| const preset = Validator.PRESETS[name] | ||
| if (!preset) { | ||
| throw new Error(`value-validator: unknown preset "${name}".`) | ||
| } | ||
| if (typeof preset === 'function') { | ||
| this._rules.push(this._wrapWithArgs(preset, args)) | ||
| return | ||
| } | ||
| // if a preset is a set, | ||
| // then ignore args | ||
| if (util.isArray(preset)) { | ||
| preset.forEach(this._add, this) | ||
| } | ||
| }) | ||
| } | ||
| _wrapWithArgs (method, args) { | ||
| // The first argument is the value | ||
| const expectedArgLength = method.length - 1 | ||
| const wrapped = wrap(method) | ||
| if (expectedArgLength !== args.length) { | ||
| const message = expectedArgLength === 1 | ||
| ? `one argument` | ||
| : `${argLength} arguments.` | ||
| throw new Error( | ||
| `value-validator: preset "${name}" only accepts ${message}` | ||
| ) | ||
| } | ||
| return function (v, callback) { | ||
| const realArgs = [v, ...args, callback] | ||
| return wrapped.apply(this, realArgs) | ||
| } | ||
| } | ||
| } | ||
| // @returns {Boolean} | ||
| function determine_pass (err, pass) { | ||
| return err | ||
| ? false | ||
| : pass === false | ||
| ? false | ||
| : true | ||
| } | ||
| function default_codec (tester) { | ||
| return tester.split('|') | ||
| .filter((tester) => { | ||
| return !!tester.trim() | ||
| }) | ||
| .map((tester) => { | ||
| tester = tester.trim() | ||
| const index = tester.indexOf(':') | ||
| if (!~index) { | ||
| return { | ||
| name: tester, | ||
| args: [] | ||
| } | ||
| } | ||
| const name = tester.slice(0, index).trim() | ||
| const args = tester.slice(index + 1) | ||
| .split(',') | ||
| .map((arg) => arg.trim()) | ||
| return { | ||
| name, | ||
| args | ||
| } | ||
| }) | ||
| } | ||
| Validator.PRESETS = {} | ||
| // Registers a global preset | ||
| Validator.registerPreset = (name, preset) => { | ||
| if (name in Validator.PRESETS) { | ||
| throw new Error(`value-validator: preset "${name}" defined.`) | ||
| } | ||
| if (typeof preset !== 'function' && !util.isArray(preset)) { | ||
| throw new TypeError( | ||
| `value-validator: preset only accepts function or array.` | ||
| ) | ||
| } | ||
| Validator.PRESETS[name] = preset | ||
| return Validator | ||
| } | ||
| Validator.registerPresets = (map) => { | ||
| let key | ||
| for (key in map) { | ||
| Validator.registerPreset(key, map[key]) | ||
| } | ||
| return Validator | ||
| } | ||
| module.exports = Validator |
| const test = require('ava') | ||
| const Validator = require('..') | ||
| Validator.registerPresets({ | ||
| 'min-length': (v, min) => { | ||
| return v.length >= Number(min) | ||
| }, | ||
| 'max-length': (v, max) => { | ||
| return v.length <= Number(max) | ||
| }, | ||
| mobile: (v) => { | ||
| return /1\d{10}/.test(v) | ||
| }, | ||
| username: function (v) { | ||
| const done = this.async() | ||
| setTimeout(() => { | ||
| if (v === 'foo') { | ||
| return done('foo already taken') | ||
| } | ||
| done(null) | ||
| }, 10) | ||
| }, | ||
| between: (v, min, max) => { | ||
| return v.length >= Number(min) && v.length <= Number(max) | ||
| }, | ||
| 'min-length-6-username': [ | ||
| 'min-length:6', | ||
| 'username' | ||
| ] | ||
| }) | ||
| test.cb('simple global preset', t => { | ||
| new Validator('mobile').validate('18800001111', (err, result) => { | ||
| t.is(err, null) | ||
| t.is(result, true) | ||
| t.end() | ||
| }) | ||
| }) | ||
| test.cb('preset with arguments', t => { | ||
| new Validator('max-length:3').validate('1234', (err, result) => { | ||
| t.is(err, null) | ||
| t.is(result, false) | ||
| t.end() | ||
| }) | ||
| }) | ||
| test.cb('preset with improper length of arguments', t => { | ||
| try { | ||
| new Validator('max-length:1,2') | ||
| } catch (e) { | ||
| t.end() | ||
| return | ||
| } | ||
| t.fail('it should throw an error.') | ||
| t.end() | ||
| }) | ||
| test.cb('multiple presets, [1, 3] test "12"', t => { | ||
| new Validator('max-length:3|min-length:1').validate('12', (err, result) => { | ||
| t.is(err, null) | ||
| t.is(result, true) | ||
| t.end() | ||
| }) | ||
| }) | ||
| test.cb('multiple presets, [1, 3] test "1234"', t => { | ||
| new Validator('max-length:3|min-length:1').validate('1234', (err, result) => { | ||
| t.is(err, null) | ||
| t.is(result, false) | ||
| t.end() | ||
| }) | ||
| }) | ||
| test.cb('multiple presets, [1, 3] test ""', t => { | ||
| new Validator('max-length:3|min-length:1').validate('', (err, result) => { | ||
| t.is(err, null) | ||
| t.is(result, false) | ||
| t.end() | ||
| }) | ||
| }) | ||
| test.cb('async preset, min:6, and username, foo, fail', t => { | ||
| new Validator('min-length:6|username').validate('foo', (err, result) => { | ||
| t.is(err, null) | ||
| t.is(result, false) | ||
| t.end() | ||
| }) | ||
| }) | ||
| test.cb('min-length-6-username, foo, fail', t => { | ||
| new Validator('min-length-6-username').validate('foo', (err, result) => { | ||
| t.is(err, null) | ||
| t.is(result, false) | ||
| t.end() | ||
| }) | ||
| }) | ||
| test.cb('async preset, min:3, and username, foo, fail', t => { | ||
| new Validator('min-length:3|username').validate('foo', (err, result) => { | ||
| t.is(err instanceof Error, true) | ||
| t.is(err.message, 'foo already taken') | ||
| t.is(result, false) | ||
| t.end() | ||
| }) | ||
| }) | ||
| test.cb('async preset, min:3, and username, bar, success', t => { | ||
| new Validator('min-length:3|username').validate('bar', (err, result) => { | ||
| t.is(err, null) | ||
| t.is(result, true) | ||
| t.end() | ||
| }) | ||
| }) | ||
| test.cb('preset with multiple arguments', t => { | ||
| new Validator('between:2,6').validate('1234', (err, result) => { | ||
| t.is(err, null) | ||
| t.is(result, true) | ||
| t.end() | ||
| }) | ||
| }) |
| const ava = require('ava') | ||
| const Validator = require('..') | ||
| const cases = [ | ||
| { | ||
| test: /\d{2,6}/, | ||
| value: '1234' | ||
| }, | ||
| { | ||
| test: /1\d{10}/, | ||
| value: '1880000', | ||
| pass: false | ||
| }, | ||
| { | ||
| title: 'function, returns boolean, fail', | ||
| test: (v) => { | ||
| return v > 10 | ||
| }, | ||
| value: 5, | ||
| pass: false | ||
| }, | ||
| { | ||
| title: 'function, returns boolean, pass', | ||
| test: (v) => { | ||
| return v > 10 | ||
| }, | ||
| value: 11 | ||
| }, | ||
| { | ||
| title: 'async function, pass', | ||
| test: function (v) { | ||
| const done = this.async() | ||
| setTimeout(() => { | ||
| if (v < 0) { | ||
| return done(null) | ||
| } | ||
| done('not minus') | ||
| }, 10) | ||
| }, | ||
| error: 'not minus', | ||
| pass: false | ||
| }, | ||
| { | ||
| title: 'function, returns Error', | ||
| test: (v) => { | ||
| if (v > 10) { | ||
| return true | ||
| } | ||
| return new Error('a') | ||
| }, | ||
| error: 'a', | ||
| pass: false | ||
| }, | ||
| { | ||
| title: 'array tester', | ||
| test: [ | ||
| /\d{11}/, | ||
| /1\d{10}/ | ||
| ], | ||
| value: '08800001111', | ||
| pass: false | ||
| } | ||
| ] | ||
| cases.forEach((c) => { | ||
| const { | ||
| title, | ||
| test, | ||
| value, | ||
| error, | ||
| pass, | ||
| only | ||
| } = c | ||
| const result = pass === false | ||
| ? false | ||
| : true | ||
| const description = title | ||
| || `${test.toString()}, ${value}, ${error ? 'fail' : 'pass'}` | ||
| const _test = only | ||
| ? ava.only.cb | ||
| : ava.cb | ||
| _test(description, t => { | ||
| let v | ||
| try { | ||
| v = new Validator(test) | ||
| } catch (e) { | ||
| console.error(e) | ||
| t.fail() | ||
| t.end() | ||
| return | ||
| } | ||
| v.validate(value, (err, success) => { | ||
| t.is(success, result) | ||
| if (err) { | ||
| t.is(err.message, error) | ||
| } else { | ||
| t.is(err, null) | ||
| } | ||
| t.end() | ||
| }) | ||
| }) | ||
| }) |
+35
-1
@@ -1,1 +0,35 @@ | ||
| {"name": "value-validator", "version": "0.0.0", "description": "", "main": "index.js", "scripts": {}, "license": "MIT"} | ||
| { | ||
| "name": "value-validator", | ||
| "version": "1.0.0", | ||
| "description": "Low-level rule manager for validating values.", | ||
| "main": "./src", | ||
| "scripts": { | ||
| "test": "ava --verbose --timeout=10s" | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git://github.com/kaelzhang/value-validator.git" | ||
| }, | ||
| "keywords": [ | ||
| "value-validator", | ||
| "validator", | ||
| "regexp", | ||
| "async" | ||
| ], | ||
| "engines": { | ||
| "node": ">=0.10.0" | ||
| }, | ||
| "author": "kaelzhang", | ||
| "license": "MIT", | ||
| "bugs": { | ||
| "url": "https://github.com/kaelzhang/value-validator/issues" | ||
| }, | ||
| "devDependencies": { | ||
| "ava": "^0.16.0" | ||
| }, | ||
| "dependencies": { | ||
| "async": "^2.0.1", | ||
| "make-array": "^1.0.1", | ||
| "wrap-as-async": "^1.2.2" | ||
| } | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Empty package
Supply chain riskPackage does not contain any code. It may be removed, is name squatting, or the result of a faulty package publish.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
14898
12315%10
900%367
Infinity%1
-66.67%1
-50%1
-50%141
Infinity%0
-100%3
Infinity%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added