├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── bench
├── README.md
├── bench-lib.js
├── bench-nolib.js
├── bench-other-libs.js
├── bench.js
└── package.json
├── build-browser.js
├── docs
├── API.md
├── CHANGELOG.md
└── vademecum.md
├── lib
├── array.js
├── boolean.js
├── common.js
├── date.js
├── error.js
├── number.js
├── object.js
└── string.js
├── package.json
├── test
├── array.js
├── boolean.js
├── date.js
├── error.js
├── number.js
├── object.js
├── string.js
├── test-runner.sh
└── test.js
├── tyval.js
└── tyval.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 | .nyc_output
17 |
18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
19 | .grunt
20 |
21 | # node-waf configuration
22 | .lock-wscript
23 |
24 | # Compiled binary addons (http://nodejs.org/api/addons.html)
25 | build/Release
26 |
27 | # Dependency directory
28 | node_modules
29 |
30 | # Optional npm cache directory
31 | .npm
32 |
33 | # Optional REPL history
34 | .node_repl_history
35 |
36 | # mac files
37 | .DS_Store
38 |
39 | # vim swap files
40 | *.swp
41 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | test
2 | bench
3 | node_modules
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '6'
4 | - '5'
5 | - '4'
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Tomas Della Vedova
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tyval
2 | [](http://standardjs.com/) [](https://travis-ci.org/delvedor/Tyval) [](https://www.npmjs.com/package/tyval)
3 |
4 | > Programs should be written for people to read, and only incidentally for machines to execute.
5 | > *[Abelson and Sussman]*
6 |
7 | **Tyval** is a validator for JavaScript, focused on **performances** and **extensibility**.
8 |
9 | The API is highly inspired from [Joi](https://github.com/hapijs/joi), but the implementation is very different. Tyval uses [code generation](https://github.com/delvedor/Tyval/blob/master/docs/vademecum.md) to achieve maximum speed when evaluating a variable.
10 | Tyval is designed to validate single values in a synchronous way and has not an error management, it always returns a boolean, *true* if all the validations has passed, *false* if at least one has failed, the design of the API forces to write atomic test, in this way the result of a single test does not influence the others.
11 |
12 |
13 | **Needs Node.js ≥ 4.0.0**
14 |
15 | [Benchmark](https://github.com/delvedor/Tyval/blob/master/bench/bench-other-libs.js) comparisons with other libraries:
16 | ```bash
17 | tyval (num) x 78,669,467 ops/sec ±1.75% (82 runs sampled)
18 | joi (num) x 37,540 ops/sec ±0.91% (89 runs sampled)
19 | validate.js (num) x 83,675 ops/sec ±1.60% (89 runs sampled)
20 | is-my-json-valid (num) x 61,898,685 ops/sec ±1.46% (88 runs sampled)
21 |
22 | tyval (str) x 81,093,089 ops/sec ±1.56% (85 runs sampled)
23 | joi (str) x 22,927 ops/sec ±1.40% (91 runs sampled)
24 | validate.js (str) x 96,270 ops/sec ±1.14% (91 runs sampled)
25 | is-my-json-valid (str) x 12,099,361 ops/sec ±1.13% (85 runs sampled)
26 | ```
27 |
28 | ## Install
29 | ```
30 | npm install tyval --save
31 | ```
32 |
33 | ## Usage
34 | Easily require it, compose a function with the chainable API and then use it.
35 | ```javascript
36 | const tyval = require('tyval')
37 |
38 | const stringValidation = tyval.string().max(10).min(1).alphanum()
39 | const numberLimits = tyval.or(tyval.number().max(1), tyval.number().min(10))
40 |
41 | function getSomeData (str, num, callback) {
42 | if (!stringValidation(str) || !numberLimits(num)) {
43 | return callback(new Error('Parameters not as expected!'), null)
44 | }
45 | // . . .
46 | }
47 | ```
48 | Were you saying composability? :)
49 | ```javascript
50 | const tyval = require('tyval')
51 | const arr = tyval.array()
52 |
53 | const arrMin = arr.min(5)
54 | const arrMax = arr.max(20)
55 | const arrRange = tyval.or(arrMin, arrMax)
56 |
57 | const arrContain = arr.contains('string')
58 | const arrContainMin = arrContain.min(5)
59 | // Needless to say that the composability
60 | // works only with validations of the same type.
61 | ```
62 | You can use it for your unit test as well!
63 | ```javascript
64 | const { test } = require('tap')
65 | const tyval = require('tyval')
66 | const generateString = require('../genStr')
67 |
68 | const stringValidation = tyval.string().max(10).min(1).alphanum()
69 |
70 | test('genStr', (t) => {
71 | t.plan(1)
72 | const result = generateString()
73 | // Here we are testing that generateString function returns
74 | // an alphanumeric string with a length between 1 and 10 characters
75 | t.true(stringValidation(result))
76 | })
77 | ```
78 |
79 |
80 | ### Browser version
81 | If you need to use Tyval inside the browser use [`tyval.min.js`](https://github.com/delvedor/Tyval/blob/master/tyval.min.js), that is generated via *browserify* and *uglify*.
82 | ```html
83 |
84 | ```
85 |
86 |
87 | ## API
88 | - tyval.string()
89 | * tyval.string().alphanum()
90 | * tyval.string().regex()
91 | * tyval.string().max()
92 | * tyval.string().min()
93 | * tyval.string().length()
94 | * tyval.string().mail()
95 | * tyval.string().ipv4()
96 | * tyval.string().ipv6()
97 | * tyval.string().base64()
98 | * tyval.string().JSON()
99 | * tyval.string().uuid()
100 | * tyval.string().MAC()
101 | * tyval.string().md5()
102 | * tyval.string().card()
103 |
104 |
105 | - tyval.number()
106 | * tyval.number().max()
107 | * tyval.number().min()
108 | * tyval.number().positive()
109 | * tyval.number().negative()
110 | * tyval.number().integer()
111 | * tyval.number().float()
112 | * tyval.number().safeInteger()
113 | * tyval.number().finite()
114 | * tyval.number().multiple()
115 | * tyval.number().notNaN()
116 | * tyval.number().port()
117 |
118 | - tyval.array()
119 | * tyval.array().max()
120 | * tyval.array().min()
121 | * tyval.array().length()
122 | * tyval.array().contains()
123 | * tyval.array().items()
124 |
125 | - tyval.date()
126 | * tyval.date().lower()
127 | * tyval.date().higher()
128 |
129 | - tyval.boolean()
130 |
131 | - tyval.object()
132 | * tyval.object().empty()
133 | * tyval.object().notNull()
134 | * tyval.object().notArray()
135 | * tyval.object().notDate()
136 | * tyval.object().notRegExp()
137 | * tyval.object().has()
138 | * tyval.object().hasNot()
139 |
140 | - tyval.error()
141 | * tyval.error().RangeError()
142 | * tyval.error().ReferenceError()
143 | * tyval.error().SyntaxError()
144 | * tyval.error().TypeError()
145 | * tyval.error().message()
146 |
147 | - tyval.or()
148 |
149 | - tyval._______.extend()
150 |
151 | ## TODO
152 | - [x] Rewrite API to improve performances
153 | - [x] Implement tyval.array()
154 | - [x] Implement max/min for array.length
155 | - [x] Refactor of the tyval object, divide functions by field (string, number, array, object...) for a better maintainability
156 | - [x] Add `Date` validator
157 | - [x] Split test in multiple files
158 | - [x] New string validation functions
159 | - [x] Browser version
160 | - [x] Improve lib code readability
161 | - [x] In toFunction, move function parameters inside function blocks to avoid naming conflicts
162 | - [x] Improve generated code readability
163 | - [x] Add `.or`functionality
164 | - [x] Remove `.toFunction()`
165 | - [ ] Add `Any` type
166 | - [ ] Make compatible extend/getArgs with es6
167 | - [ ] Add `.not`functionality eg: `tyval.not.string()`
168 |
169 | ## Contributing
170 | If you feel you can help in any way, be it with examples, extra testing, or new features please open a pull request or open an issue.
171 |
172 | Do you want to know more how this library is built?
173 | Have a look [here](https://github.com/delvedor/Tyval/blob/master/docs/vademecum.md)!
174 |
175 | I would make a special thanks to [@mcollina](https://github.com/mcollina) for helping me to improving the code.
176 |
177 | The code follows the Standard code style.
178 | [](https://github.com/feross/standard)
179 |
180 | ## License
181 | **[MIT](https://github.com/delvedor/Tyval/blob/master/LICENSE)**
182 |
183 | *The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and non infringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.*
184 |
185 | Copyright © 2016 Tomas Della Vedova
186 |
--------------------------------------------------------------------------------
/bench/README.md:
--------------------------------------------------------------------------------
1 | # Tyval
2 |
3 | ## Benchmark
4 |
5 | The benchmarks are divided in two separated bench, `nolib` and `lib`.
6 | As you can imagine the `nolib` is the bench without tyval, `lib` is the bench with tyval.
7 |
8 | These benchmarks are used to improve the overall performances and find perf issues.
9 | PR are welcome.
10 | ___
11 | These benchmarks where taken via [benchmark.js](https://github.com/bestiejs/benchmark.js/) on Node v6.2.0, on a MacBook Pro Retina Late 2013 (i7, 16GB of RAM).
12 | ```bash
13 | Benchmarking nolib
14 | numTest x 27,342,295 ops/sec ±1.00% (87 runs sampled)
15 | numTest-false x 76,810,306 ops/sec ±1.62% (85 runs sampled)
16 | strTest x 14,052,643 ops/sec ±1.14% (84 runs sampled)
17 | strTest-false x 10,178,614 ops/sec ±1.01% (86 runs sampled)
18 | arrayTest x 32,832,476 ops/sec ±1.18% (85 runs sampled)
19 | arrayTest-false x 33,072,660 ops/sec ±1.06% (90 runs sampled)
20 | objTest x 25,616,040 ops/sec ±1.05% (88 runs sampled)
21 | objTest-false x 32,293,965 ops/sec ±1.14% (87 runs sampled)
22 | objHas x 6,456,075 ops/sec ±1.02% (89 runs sampled)
23 | objHas-false x 6,468,464 ops/sec ±1.01% (88 runs sampled)
24 |
25 | Benchmarking lib
26 | numTest x 27,805,074 ops/sec ±3.56% (86 runs sampled)
27 | numTest-false x 80,597,703 ops/sec ±1.55% (88 runs sampled)
28 | strTest x 14,342,357 ops/sec ±1.16% (87 runs sampled)
29 | strTest-false x 10,069,206 ops/sec ±1.03% (88 runs sampled)
30 | arrayTest x 32,771,117 ops/sec ±1.09% (88 runs sampled)
31 | arrayTest-false x 33,026,228 ops/sec ±1.20% (91 runs sampled)
32 | objTest x 25,807,471 ops/sec ±0.94% (89 runs sampled)
33 | objTest-false x 32,314,996 ops/sec ±1.06% (86 runs sampled)
34 | objHas x 6,273,742 ops/sec ±1.17% (88 runs sampled)
35 | objHas-false x 6,510,533 ops/sec ±0.80% (89 runs sampled)
36 | objHas(fast) x 58,913,622 ops/sec ±1.58% (87 runs sampled)
37 | objHas(fast)-false x 25,290,817 ops/sec ±0.87% (86 runs sampled)
38 |
39 | Done!
40 | ```
41 | [Benchmark](https://github.com/delvedor/Tyval/blob/master/bench/bench-other-libs.js) comparisons with other libraries:
42 | ```bash
43 | tyval (num) x 78,669,467 ops/sec ±1.75% (82 runs sampled)
44 | joi (num) x 37,540 ops/sec ±0.91% (89 runs sampled)
45 | validate.js (num) x 83,675 ops/sec ±1.60% (89 runs sampled)
46 | is-my-json-valid (num) x 61,898,685 ops/sec ±1.46% (88 runs sampled)
47 |
48 | tyval (str) x 81,093,089 ops/sec ±1.56% (85 runs sampled)
49 | joi (str) x 22,927 ops/sec ±1.40% (91 runs sampled)
50 | validate.js (str) x 96,270 ops/sec ±1.14% (91 runs sampled)
51 | is-my-json-valid (str) x 12,099,361 ops/sec ±1.13% (85 runs sampled)
52 | ```
53 |
--------------------------------------------------------------------------------
/bench/bench-lib.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Benchmark = require('benchmark')
4 | const suite = Benchmark.Suite()
5 | const tyval = require('../tyval')
6 |
7 | const numTest = tyval.number().min(-5).max(10).integer().finite().safeInteger()
8 | const strTest = tyval.string().min(5).max(10).alphanum()
9 | const arrayTest = tyval.array().max(10).min(2)
10 | const objTest = tyval.object().notNull().notArray().notDate().notRegExp()
11 | const objHas = tyval.object().has('test').has('bench').hasNot('nope')
12 | const objHasFast = tyval.object().has('test', { fast: true }).has('bench', { fast: true }).hasNot('nope', { fast: true })
13 |
14 | let objToTest = {
15 | test: 'test42',
16 | bench: 5
17 | }
18 |
19 | suite
20 | .add('numTest', function () {
21 | numTest(5)
22 | })
23 | .add('numTest-false', function () {
24 | numTest(-50)
25 | })
26 | .add('strTest', function () {
27 | strTest('abc123')
28 | })
29 | .add('strTest-false', function () {
30 | strTest('abcdef')
31 | })
32 | .add('arrayTest', function () {
33 | arrayTest([1, 2, 3])
34 | })
35 | .add('arrayTest-false', function () {
36 | arrayTest([1])
37 | })
38 | .add('objTest', function () {
39 | objTest({})
40 | })
41 | .add('objTest-false', function () {
42 | objTest([])
43 | })
44 | .add('objHas', function () {
45 | objHas({test: 1, bench: 2})
46 | })
47 | .add('objHas-false', function () {
48 | objHas({test: 1, bench: 2, nope: 3})
49 | })
50 | .add('objHas(fast)', function () {
51 | objHasFast({test: 1, bench: 2})
52 | })
53 | .add('objHas(fast)-false', function () {
54 | objHasFast({test: 1, bench: 2, nope: 3})
55 | })
56 | .add('combined obj and str', function () {
57 | objHas(objToTest) && strTest(objToTest.test) && numTest(objToTest.bench)
58 | })
59 | .add('combined obj and str - fast', function () {
60 | objHasFast(objToTest) && strTest(objToTest.test) && numTest(objToTest.bench)
61 | })
62 | .on('cycle', function (event) {
63 | console.log(String(event.target))
64 | })
65 | .on('complete', function () {})
66 | .run()
67 |
--------------------------------------------------------------------------------
/bench/bench-nolib.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Benchmark = require('benchmark')
4 | const suite = Benchmark.Suite()
5 |
6 | // Emulates the number test
7 | // const numTest = tyval.number().min(-5).max(10).integer().finite().safeInteger().toFunction()
8 | const numTest = function (number) {
9 | let bool = true
10 | bool = bool && typeof number === 'number'
11 | bool = bool && number >= -5
12 | bool = bool && number <= 10
13 | bool = bool && Number.isInteger(number)
14 | bool = bool && Number.isFinite(number)
15 | bool = bool && Number.isSafeInteger(number)
16 | return bool
17 | }
18 |
19 | // Emulates the string test
20 | // const strTest = tyval.string().min(5).max(10).alphanum().toFunction()
21 | const strTest = function (string) {
22 | let bool = true
23 | bool = bool && typeof string === 'string'
24 | bool = bool && string.length >= 5
25 | bool = bool && string.length <= 10
26 | let reg = /((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+[0-9a-z]+$/i
27 | bool = bool && reg.test(string)
28 | return bool
29 | }
30 |
31 | // Emulates the array test
32 | // const arrayTest = tyval.array().max(10).min(2).toFunction()
33 | const arrayTest = function (array) {
34 | let bool = true
35 | bool = bool && Array.isArray(array)
36 | bool = bool && array.length <= 10
37 | bool = bool && array.length >= 2
38 | return bool
39 | }
40 |
41 | // Emulates the object test
42 | // const objTest = tyval.object().notNull().notArray().notDate().notRegExp().toFunction()
43 | const objTest = function (obj) {
44 | let bool = true
45 | bool = bool && typeof obj === 'object'
46 | bool = bool && obj !== null
47 | bool = bool && !Array.isArray(obj)
48 | bool = bool && !(obj instanceof Date)
49 | bool = bool && !(obj instanceof RegExp)
50 | return bool
51 | }
52 |
53 | const objHas = function (obj) {
54 | let bool = true
55 | bool = bool && typeof obj === 'object'
56 | bool = bool && obj.hasOwnProperty('test')
57 | bool = bool && obj.hasOwnProperty('bench')
58 | bool = bool && !obj.hasOwnProperty('nope')
59 | return bool
60 | }
61 |
62 | let objToTest = {
63 | test: 'test42',
64 | bench: 5
65 | }
66 |
67 | suite
68 | .add('numTest', function () {
69 | numTest(5)
70 | })
71 | .add('numTest-false', function () {
72 | numTest(-50)
73 | })
74 | .add('strTest', function () {
75 | strTest('abc123')
76 | })
77 | .add('strTest-false', function () {
78 | strTest('abcdef')
79 | })
80 | .add('arrayTest', function () {
81 | arrayTest([1, 2, 3])
82 | })
83 | .add('arrayTest-false', function () {
84 | arrayTest([1])
85 | })
86 | .add('objTest', function () {
87 | objTest({})
88 | })
89 | .add('objTest-false', function () {
90 | objTest([])
91 | })
92 | .add('objHas', function () {
93 | objHas({test: 1, bench: 2})
94 | })
95 | .add('objHas-false', function () {
96 | objHas({test: 1, bench: 2, nope: 3})
97 | })
98 | .add('combined obj and str', function () {
99 | objHas(objToTest) && strTest(objToTest.test) && numTest(objToTest.bench)
100 | })
101 | .on('cycle', function (event) {
102 | console.log(String(event.target))
103 | })
104 | .on('complete', function () {})
105 | .run()
106 |
--------------------------------------------------------------------------------
/bench/bench-other-libs.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Benchmark = require('benchmark')
4 | const suite = Benchmark.Suite()
5 |
6 | // Libraries
7 | const tyval = require('../tyval')
8 | const Joi = require('joi')
9 | const validatejs = require('validate.js')
10 | const jsonValid = require('is-my-json-valid')
11 |
12 | // Number validations
13 | const tyvalNum = tyval.number().min(-5).max(10).integer()
14 | const joiNum = Joi.number().min(-5).max(10).integer()
15 | const validatejsNum = { numericality: { greaterThanOrEqualTo: -5, lessThanOrEqualTo: 10, onlyInteger: true } }
16 | const jsonValidNum = jsonValid({
17 | type: 'integer',
18 | minimum: -5,
19 | maximum: 10
20 | })
21 | let num = Math.floor(Math.random() * 15) - 5
22 |
23 | // String validations
24 | const tyvalStr = tyval.string().min(1).max(20)
25 | const joiStr = Joi.string().min(1).max(20)
26 | const validatejsStr = { length: { minimum: 1, maximum: 20 } }
27 | const jsonValidStr = jsonValid({
28 | type: 'string',
29 | minimum: 1,
30 | maximum: 20
31 | })
32 | let str = 'Benchmarks!'
33 |
34 | const tyvalItems = tyval.array().items(tyvalStr)
35 | const joiItems = Joi.array().items(joiStr)
36 | let arr = ['a', 'bb', 'ccc', 'dddd', 'eeeee', 'ffffff', 'ggggggg', 'hhhhhhhh', 'iiiiiiiii', 'llllllllll']
37 |
38 | suite
39 | .add('tyval (num)', function () {
40 | tyvalNum(num)
41 | })
42 | .add('joi (num)', function () {
43 | Joi.validate(num, joiNum)
44 | })
45 | .add('validate.js (num)', function () {
46 | validatejs.single(num, validatejsNum)
47 | })
48 | .add('is-my-json-valid (num)', function () {
49 | jsonValidNum(num)
50 | })
51 | .add('tyval (str)', function () {
52 | tyvalStr(str)
53 | })
54 | .add('joi (str)', function () {
55 | Joi.validate(str, joiStr)
56 | })
57 | .add('validate.js (str)', function () {
58 | validatejs.single(str, validatejsStr)
59 | })
60 | .add('is-my-json-valid (str)', function () {
61 | jsonValidStr(str)
62 | })
63 | .add('tyval (array)', function () {
64 | tyvalItems(arr)
65 | })
66 | .add('joi (array)', function () {
67 | Joi.validate(arr, joiItems)
68 | })
69 | .on('cycle', function (event) {
70 | console.log(String(event.target))
71 | })
72 | .on('complete', function () {})
73 | .run()
74 |
--------------------------------------------------------------------------------
/bench/bench.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const chalk = require('chalk')
4 |
5 | console.log(chalk.yellow('Benchmarking nolib'))
6 | require('./bench-nolib')
7 |
8 | console.log(chalk.yellow('\nBenchmarking lib'))
9 | require('./bench-lib')
10 |
11 | console.log(chalk.yellow('\nBenchmarking other-libs'))
12 | require('./bench-other-libs')
13 |
14 | console.log(chalk.yellow('\nDone!'))
15 |
--------------------------------------------------------------------------------
/bench/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bench",
3 | "version": "1.0.0",
4 | "description": "## Benchmark",
5 | "main": "bench.js",
6 | "private": true,
7 | "license": "MIT",
8 | "devDependencies": {
9 | "is-my-json-valid": "^2.13.1",
10 | "joi": "^8.4.2",
11 | "validate.js": "^0.10.0"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/build-browser.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const fs = require('fs')
4 | const pump = require('pump')
5 | const browserify = require('browserify')
6 | const { minify } = require('uglify-js')
7 | const replaceStream = require('replacestream')
8 | const selfStream = require('self-stream')
9 |
10 | // Streams
11 | const brBabel = browserify('./tyval.js').transform('babelify', { presets: ['es2015'] }).bundle()
12 | const ws = fs.createWriteStream('./bundle.js')
13 | const rs = replaceStream('[function(require,module,exports){"use strict";module.exports=', '[function(require,module,exports){"use strict";window.tyval=')
14 |
15 | browserifyCode()
16 |
17 | function browserifyCode () {
18 | console.log('> Start browserify')
19 | console.log('> Start babelify')
20 | pump(brBabel, ws, (err) => {
21 | if (err) return err
22 | console.log('< End babelify')
23 | console.log('< End browserify')
24 | uglifyCode()
25 | })
26 | }
27 |
28 | function uglifyCode () {
29 | console.log('> Start uglify')
30 | const { code } = minify('./bundle.js', { mangle: false })
31 | fs.writeFile('./tyval.min.js', code, 'utf8', (err) => {
32 | if (err) return console.log(err)
33 | console.log('< End uglify')
34 | replaceExports()
35 | })
36 | }
37 |
38 | function replaceExports () {
39 | console.log('> Start replace')
40 | selfStream('./tyval.min.js', rs, (err) => {
41 | if (err) return console.log(err)
42 | console.log('< End replace')
43 | fs.unlink('./bundle.js', (err) => {
44 | if (err) return console.log(err)
45 | console.log('Done!')
46 | })
47 | })
48 | }
49 |
--------------------------------------------------------------------------------
/docs/API.md:
--------------------------------------------------------------------------------
1 | # Tyval [](https://www.npmjs.com/package/tyval)
2 | ## API
3 | - tyval.string()
4 | * tyval.string().alphanum()
5 | * tyval.string().regex()
6 | * tyval.string().max()
7 | * tyval.string().min()
8 | * tyval.string().length()
9 | * tyval.string().mail()
10 | * tyval.string().ipv4()
11 | * tyval.string().ipv6()
12 | * tyval.string().base64()
13 | * tyval.string().JSON()
14 | * tyval.string().uuid()
15 | * tyval.string().MAC()
16 | * tyval.string().md5()
17 | * tyval.card().card()
18 |
19 |
20 | - tyval.number()
21 | * tyval.number().max()
22 | * tyval.number().min()
23 | * tyval.number().positive()
24 | * tyval.number().negative()
25 | * tyval.number().integer()
26 | * tyval.number().float()
27 | * tyval.number().safeInteger()
28 | * tyval.number().finite()
29 | * tyval.number().multiple()
30 | * tyval.number().notNaN()
31 | * tyval.number().port()
32 |
33 | - tyval.array()
34 | * tyval.array().max()
35 | * tyval.array().min()
36 | * tyval.array().length()
37 | * tyval.array().contains()
38 | * tyval.array().items()
39 |
40 | - tyval.date()
41 | * tyval.date().lower()
42 | * tyval.date().higher()
43 |
44 | - tyval.boolean()
45 |
46 | - tyval.object()
47 | * tyval.object().empty()
48 | * tyval.object().notNull()
49 | * tyval.object().notArray()
50 | * tyval.object().notDate()
51 | * tyval.object().notRegExp()
52 | * tyval.object().has()
53 | * tyval.object().hasNot()
54 |
55 | - tyval.error()
56 | * tyval.error().RangeError()
57 | * tyval.error().ReferenceError()
58 | * tyval.error().SyntaxError()
59 | * tyval.error().TypeError()
60 | * tyval.error().message()
61 |
62 | - tyval.or()
63 |
64 | - tyval._______.extend()
65 |
66 | ___
67 |
68 |
69 | ### tyval.string()
70 | Checks if the `value` is a string.
71 |
72 |
73 | #### .string().alphanum()
74 | Checks if the `value` is alphanumerical.
75 |
76 |
77 | #### .string().regex(regex)
78 | Test the regex passed as input on the `value`.
79 | `regex` is the regex code.
80 |
81 |
82 | #### .string().max(number)
83 | Checks if the `value.length` is lower than the passed max value.
84 | `number` is the number value to check.
85 |
86 |
87 | #### .string().min(number)
88 | Checks if the `value.length` is higher than the passed min value.
89 | `number` is the number value to check.
90 |
91 |
92 | #### .string().length(number)
93 | Checks if the `value.length` is equal than the passed value.
94 | `number` is the number value to check.
95 |
96 |
97 | #### .string().mail()
98 | Checks if the `value` is a valid mail string.
99 |
100 |
101 | #### .string().ipv4()
102 | Checks if the `value` is a valid ipv4 string.
103 |
104 |
105 | #### .string().ipv6()
106 | Checks if the `value` is a valid ipv6 string.
107 |
108 |
109 | #### .string().base64()
110 | Checks if the `value` is a valid base64 string.
111 |
112 |
113 | #### .string().JSON()
114 | Checks if the `value` is a valid JSON.
115 |
116 |
117 | #### .string().uuid()
118 | Checks if the `value` is a valid uuid string.
119 |
120 |
121 | #### .string().MAC()
122 | Checks if the `value` is a valid MAC address.
123 |
124 |
125 | #### .string().md5()
126 | Checks if the `value` is a valid md5 string.
127 |
128 |
129 | #### .string().card(cardType)
130 | Checks if the `value` is a valid card code string.
131 | Accepted cards are: *jcb*, *visa*, *discover*, *dinersclub*, *mastercard*, *americanexpress*
132 |
133 | ___
134 |
135 | ### tyval.number()
136 | Checks if the `value` is a number.
137 |
138 |
139 | #### .number().max(number)
140 | Checks if the `value` is lower than the passed max value.
141 | `number` is the number value to check.
142 |
143 |
144 | #### .number().min(number)
145 | Checks if the `value` is higher than the passed min value.
146 | `number` is the number value to check.
147 |
148 |
149 | #### .number().positive()
150 | Checks if the `value` is positive.
151 |
152 |
153 | #### .number().negative()
154 | Checks if the `value` is negative.
155 |
156 |
157 | #### .number().integer()
158 | Checks if the `value` is an integer.
159 | good
160 |
161 | #### .number().float()
162 | Checks if the `value` is a float.
163 |
164 |
165 | #### .number().safeInteger()
166 | Checks if the `value` is a safeInteger.
167 |
168 |
169 | #### .number().finite()
170 | Checks if the `value` is finite.
171 |
172 |
173 | #### .number().multiple(number)
174 | Checks if the `value` is a multiple of the passed value.
175 | `number` is the multiple number value to check.
176 |
177 |
178 | #### .number().notNaN()
179 | Checks if the `value` is not a NaN.
180 |
181 |
182 | #### .number().port(options)
183 | Checks if the `value` is a valid network port number.
184 | If `reserved` is equal to true, the test returns false if the port number is lower than 1024, default to *false*. Usage: `.number().port(3000, { reserved: true })`.
185 |
186 | ___
187 |
188 | ### tyval.array()
189 | Checks if the `value` is an array.
190 |
191 |
192 | #### .array().max(number)
193 | Checks if the `value.length` is lower than the passed max value.
194 | `number` is the number value to check.
195 |
196 |
197 | #### .array().min(number)
198 | Checks if the `value.length` is higher than the passed min value.
199 | `number` is the number value to check.
200 |
201 |
202 | #### .array().length(number)
203 | Checks if the `value.length` is the same as the passed value.
204 | `number` is the length number value to check.
205 |
206 |
207 | #### .array().contains(value)
208 | Checks if the array `value` contains the passed value
209 |
210 |
211 | #### .array().items(function)
212 | Checks if every array item is valid using the function passed as parameter.
213 | Example:
214 | ```javascript
215 | const str = tyval.string().min(1).max(10)
216 | const items = tyval.array().items(str)
217 | ```
218 |
219 | ___
220 |
221 | ### tyval.date()
222 | Checks if the `value` is a date.
223 |
224 |
225 | #### .date().lower(date)
226 | Checks if the `value.getTime()` is lower than the passed value.
227 | `date` is the date object to compare
228 |
229 |
230 | #### .date().higher(date)
231 | Checks if the `value.getTime()` is higher than the passed value.
232 | `date` is the date object to compare
233 |
234 | ___
235 |
236 | ### tyval.boolean()
237 | Checks if the `value` is a boolean.
238 |
239 | ___
240 |
241 | ### tyval.object()
242 | Checks if the `value` is an object.
243 |
244 |
245 | #### .object().empty()
246 | Checks if the `value` object is empty.
247 |
248 |
249 | #### .object().notNull()
250 | Checks if the `value` object is not null.
251 | This because `typeof null = 'object'`
252 |
253 |
254 | #### .object().notArray()
255 | Checks if the `value` object is not an array.
256 | This because `typeof [] = 'object'`
257 |
258 |
259 | #### .object().notDate()
260 | Checks if the `value` object is not a date.
261 | This because `typeof new Date() = 'object'`
262 |
263 |
264 | #### .object().notRegExp()
265 | Checks if the `value` object is not a RegExp.
266 | This because `typeof new RegExp() = 'object'`
267 |
268 |
269 | #### .object().has(key, options)
270 | Checks if the `value` object has the key passed as string.
271 | If `fast` is *true* the overall performances gets ~10x speed, but the test fails if the key value exist and is equal to *undefined*, default to *false*. Usage: `.object().has('key', { fast: true })`
272 |
273 |
274 |
275 | #### .object().hasNot(key, options)
276 | Checks if the `value` object has not the key passed as string.
277 | If `fast` is *true* the overall performances gets ~4x speed, but the test fails if the key value exist and is equal to *undefined*, default to *false*. Usage: `.object().hasNot('key', { fast: true })`
278 |
279 | ___
280 |
281 | ### tyval.error()
282 | Checks if the `value` is an instance of `Error`
283 |
284 |
285 | #### .error().RangeError()
286 | Checks if the `value` is an instance of `RangeError`
287 |
288 |
289 | #### .error().ReferenceError()
290 | Checks if the `value` is an instance of `ReferenceError`
291 |
292 |
293 | #### .error().SyntaxError()
294 | Checks if the `value` is an instance of `SyntaxError`
295 |
296 |
297 | #### .error().TypeError()
298 | Checks if the `value` is an instance of `TypeError`
299 |
300 |
301 | #### .error().message(msg)
302 | Checks if the error message is the same as the given parameter.
303 | `msg` must be a string.
304 |
305 | ___
306 |
307 | ### tyval.or(...)
308 | With this function you can compose a new validator by combining other tyval validators.
309 | The parameters *must be* functions.
310 | Example:
311 | ```javascript
312 | const numMax = tyval.number().max(1)
313 | const numMin = tyval.number().min(10)
314 | // represents n < 1 || n > 10
315 | const numberLimits = tyval.or(numMax, numMin)
316 |
317 | console.log(numberLimits(-3)) // true
318 | console.log(numberLimits(20)) // true
319 | console.log(numberLimits(5)) // false
320 | ```
321 |
322 | ___
323 |
324 | ### tyval._______.extend(function)
325 | Adds a new validator to tyval.
326 | **Inside the `_______` field you must put the type of validator you need to extend.**
327 | You can access the value to validate via `value`
328 | Use `if (condition) { return false }` to elaborate your validation.
329 | Usage:
330 | ```javascript
331 | tyval./*type you need to extend*/.extend(function someName () {
332 | // your validation code
333 | if (/* your boolean validator */) {
334 | return false
335 | }
336 | })
337 | ```
338 | Example:
339 | ```javascript
340 | tyval.number.extend(function isZero () {
341 | if (value !== 0) {
342 | return false
343 | }
344 | })
345 | // let's use the extended function
346 | const zero = tyval.number().isZero()
347 | if (zero(0)) {
348 | console.log('is equal to zero :D')
349 | }
350 | ```
351 | If you need to pass some `parameter` to the function:
352 | ```javascript
353 | tyval./*type you need to extend*/.extend(function someName (param) {
354 | // your validation code
355 | console.log($param$)
356 | if (/* your boolean validator */) {
357 | return false
358 | }
359 | })
360 | ```
361 | As you can imagine, `value` is a reserved name of **Tyval**, see [here](https://github.com/delvedor/Tyval/blob/master/docs/vademecum.md) why.
362 | If you are passing some variable in your function, write it with `'$'` inside your code, as you can see in the example, see [here](https://github.com/delvedor/Tyval/blob/master/docs/vademecum.md#whydollar) why.
363 | ```javascript
364 | // usage example with a parameter
365 | tyval.number.extend(function lessThan (num) {
366 | if (value > $num$) {
367 | return false
368 | }
369 | })
370 | // let's use the extended function with a parameter
371 | const ltf = tyval.number().lessThan(50)
372 | if (ltf(10)) {
373 | console.log('is less than 50!')
374 | }
375 | ```
376 | *Did you made a cool validator? Open a pull request! ;)*
377 |
--------------------------------------------------------------------------------
/docs/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v4.0.0
4 | - Removed `.toFunction()`
5 | - Moved from `errors++` to `return false`
6 | - Refactor of library internal code
7 | - Composability! :)
8 | - Changed *fast* argument in object.has and .object.hasNot
9 | - Changed *reserved* argument in number.port
10 | - Added more type checks
11 |
12 | ## v3.4.0
13 | - Improved generated code readability
14 | - Added `or` function
15 |
16 | ## v3.3.0
17 | - Now *.toFunction()* supports `function.toString()`
18 | - Added `error` type
19 | - Added *error.RangeError*, *error.ReferenceError*, *error.SyntaxError*, *error.TypeError*, *error.message*
20 | - Added *string.card*
21 | - Added *array.items*
22 |
23 | ## v3.2.0
24 | - Now all validators use `if (condition) { errors++ }` statement instead of `state = state && condition`
25 | - Rewrited *.toFunction()* method
26 | - Updated *.extend()* method
27 | - Updated *.integer()*, *.float()* and *.safeInteger()*
28 | - Added *.npmignore*
29 |
30 | ## v3.1.0
31 | - Added *string.base64*, *string.JSON*, *string.uuid*, *string.MAC*, *string.md5*
32 |
33 | ## v3.0.0
34 | - New `validator` array
35 | - Removed `parameters` object
36 | - Rewrite of the API according the new validator array
37 | - Now all the parameters are block scoped
38 | - Renamed `check` to `state`
39 | - Renamed `variable` to `value`
40 | - Moved `extend` function to `common` utility
41 | - Rewrited `extend` function
42 | - Now `extend` function is easy to use
43 | - Rewrited `toFunction` function
44 | - Added blocking errors in `common` functions
45 | - Fixed tests
46 | - Updated dev deps
47 | - Updated browser script
48 |
49 | ## v2.6.2
50 | - Fix typo in build-browser
51 | - Regenerated the broswerify version
52 |
53 | ## v2.6.1
54 | - Updated ipv6 RegExp
55 |
56 | ## v2.6.0
57 | - Added Browser version
58 |
59 | ## v2.5.0
60 | - Added *string.mail*, *string.ipv4*, *string.ipv6*
61 | - Added *number.port*
62 | - Refactored toFunction
63 | - Removed esprima/estraverse/escodegen dependencies
64 |
65 | ## v2.4.0
66 | - Added *object.notNull*, *object.notArray*, *object.notDate*, *object.notRegExp*, *object.has* and *object.hasNot*
67 | - Added *array.contains*
68 | - More testing
69 | - Moved from ava to tap for testing
70 | - More benchmark
71 |
72 | ## v2.3.0
73 | - Added *date.lower* and *date.higher* validators
74 | - Added *object.empty* validator
75 | - Added *string.length* validator
76 | - Added *number.notNaN* validator
77 | - Splitted test in multiple files
78 |
79 | ## v2.2.0
80 | - Splitted code by type inside lib/ folder
81 | - Changed *extend* implementation
82 | - Added *Date* method
83 | - Renamed API
84 | - Dramatically improved performance
85 | - Updated *toFunction* method
86 |
87 | ## v2.1.0
88 | - Added toArray, maxArray and minArray
89 | - Updated test
90 |
91 | ## v2.0.0
92 | - Complete rewrite of the API
93 | - Rewrited test
94 | - Added benchmarks
95 |
96 | ## v1.0.0
97 | - Initial implementation.
98 |
--------------------------------------------------------------------------------
/docs/vademecum.md:
--------------------------------------------------------------------------------
1 | # Tyval [](https://www.npmjs.com/package/tyval)
2 |
3 | ## How works this library?
4 | **Tyval** has two main goals:
5 | - **Speed**
6 | - **Extensibility**
7 |
8 | To achieve this two goals the lib adopted few decisions and technical implementations.
9 | Below you will find all the main parts of the code and their explanation.
10 |
11 | ### toFunction method
12 | This method is the core of the library, its purpose is to take all the validation functions and merge them into a single function via code generation. To achieve the *composability* all the type-validator-specific methods are added to the generated function.
13 | ```javascript
14 | toFunction: function (validatorObject) {
15 | return (context, validatorFunction, validatorParameters) => {
16 | // Returns an array with every line of the function
17 | // Here we remove the function declaration,
18 | // this works ONLY if there are not destructuring assignment as parameters.
19 | // Because of the lib design the validator function has never parameters,
20 | // so we can be "safe" about the following implementation.
21 | const linesOfCode = func => {
22 | func = func.toString()
23 | return func.substring(func.indexOf('{') + 1, func.lastIndexOf('}'))
24 | .split('\n')
25 | .filter(line => line.trim() !== '') // Removes empty lines
26 | }
27 |
28 | let code = ''
29 | // if the validator has already been defined
30 | if (context !== null) {
31 | let lines = linesOfCode(context)
32 | // Gets the number of spaces between
33 | // the beginning of the string and the first character
34 | let spaces = lines[0].search(/\S/)
35 | // Formats the indentation
36 | lines.forEach((line, index) => {
37 | if (index === lines.length - 1) return
38 | if (line.trim() === '{') spaces = line.search(/\S/)
39 | code += `
40 | ${line.slice(spaces)}`
41 | })
42 | // if is a new validator
43 | } else {
44 | // Function code
45 | code = `
46 | "use strict"
47 | `
48 | }
49 |
50 | code += `
51 | {`
52 | const lines = linesOfCode(validatorFunction)
53 | const spaces = lines[0].search(/\S/)
54 |
55 | lines.forEach(line => {
56 | for (let val in validatorParameters) {
57 | let value
58 | if (typeof validatorParameters[val] === 'string') {
59 | value = `'${validatorParameters[val]}'`
60 |
61 | // If the variable is an object (but not an instance of RegExp) we stringify it
62 | } else if (typeof validatorParameters[val] === 'object' && !(validatorParameters[val] instanceof RegExp)) {
63 | value = JSON.stringify(validatorParameters[val])
64 |
65 | // If the variable is a function
66 | } else if (typeof validatorParameters[val] === 'function') {
67 | value = validatorParameters[val].toString()
68 |
69 | // In all the other cases we add it 'as is' to the code
70 | } else {
71 | value = validatorParameters[val]
72 | }
73 | // Replace $varname$ with its value
74 | line = line.replace(new RegExp('\\' + val.substring(0, val.length - 1) + '\\$', 'g'), value)
75 | }
76 | code += `
77 | ${line.slice(spaces)}`
78 | })
79 | // Ends the block scope
80 | code += `
81 | };`
82 |
83 | code += `
84 | return true`
85 |
86 | // Appends all the validator functions to the newly generated function
87 | const func = new Function('value', code)
88 | Object.keys(validatorObject).forEach(val => {
89 | func[val] = validatorObject[val]
90 | })
91 |
92 | // Fix for .length property
93 | Object.defineProperty(func, 'length', {
94 | writable: true
95 | })
96 | if (typeof validatorObject.length === 'function') {
97 | func.length = validatorObject.length
98 | }
99 |
100 | return func
101 | }
102 | }
103 | ```
104 | See the [full code](https://github.com/delvedor/Tyval/blob/master/lib/common.js)!
105 |
106 | **Real world example:**
107 | This following code
108 | ```javascript
109 | const strTest = tyval.string().min(5).max(10).alphanum()
110 | ```
111 | generates:
112 | ```javascript
113 | function (value) {
114 | "use strict"
115 | {
116 | if (typeof value !== 'string') {
117 | return false
118 | }
119 | };{
120 | if (value < 5) {
121 | return false
122 | }
123 | };{
124 | if (value > 10) {
125 | return false
126 | }
127 | };{
128 | const reg = /((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+[0-9a-z]+$/i;
129 | if (!reg.test(value)) {
130 | return false
131 | }
132 | };
133 | return true
134 | }
135 | ```
136 | Before version 3.2.0, the validator was checked by a boolean assign, `state = state && condition`.
137 | From version 4.0.0, Tyval uses the following implementation, `if (condition) { return false }`, because has better performances.
138 |
139 |
140 | ### Why $varname$
141 | Inside the parameters object every key is saved as `$varname$ : value`, the `'$'` are used during the code generation to replace the `$varname$` with his value to improve performances.
142 | Example:
143 | ```javascript
144 | if (value > $max$) { ... }
145 | // assuming $max$ is equal to 5,
146 | // after code generation becomes:
147 | if (value > 5) { ... }
148 | ```
149 |
150 | ### extend method
151 | Extensibility is one of the core concept of Tyval, with the version 3.0.0 the `extend` function has been rewrited and simplified its use.
152 | ```javascript
153 | extend: function (tyvalValidator, func, toFunction) {
154 | // Thanks to: https://davidwalsh.name/javascript-arguments
155 | // gets the name of the arguments of a function
156 | const getArgs = func => {
157 | // First match everything inside the function argument parens.
158 | let args = func.toString().match(/function\s.*?\(([^)]*)\)/)[1]
159 | // Split the arguments string into an array comma delimited.
160 | return args.split(',').map(arg => {
161 | // Ensure no inline comments are parsed and trim the whitespace.
162 | return arg.replace(/\/\*.*\*\//, '').trim()
163 | }).filter(arg => {
164 | // Ensure no undefined values are added.
165 | return arg
166 | })
167 | }
168 |
169 | // Gets the parameters name
170 | const parametersName = getArgs(func)
171 |
172 | // Extends the passed tyval validator with a new function
173 | tyvalValidator[func.name] = function () {
174 | // gets the parameters passed as arguments
175 | const parametersValue = Array.prototype.slice.call(arguments)
176 | if (parametersName.length !== parametersValue.length) {
177 | throw new Error('The length of parametersName and parametersValue do not coincide')
178 | }
179 |
180 | // Instantiate the parameters object
181 | const parameters = {}
182 | for (let i = 0; i < parametersName.length; i++) {
183 | // Adds the parameters name: value
184 | parameters['$' + parametersName[i] + '$'] = parametersValue[i]
185 | }
186 |
187 | return toFunction(this, func, parameters)
188 | }
189 | }
190 | ```
191 | See the [full code](https://github.com/delvedor/Tyval/blob/master/lib/common.js)!
192 |
--------------------------------------------------------------------------------
/lib/array.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* globals value */
4 | /* eslint-disable no-undef */
5 |
6 | const buildToFunction = require('./common').toFunction
7 | const extend = require('./common').extend
8 |
9 | // checks if the value is an array
10 | const array = function () {
11 | return toFunction(null, function () {
12 | if (!Array.isArray(value)) {
13 | return false
14 | }
15 | })
16 | }
17 |
18 | // checks if the array.length is higher than the passed value
19 | array.max = function (max) {
20 | if (typeof max !== 'number') {
21 | throw new TypeError('array.max - max is not a number')
22 | }
23 | return toFunction(this, function () {
24 | if (value.length > $max$) {
25 | return false
26 | }
27 | }, { $max$: max })
28 | }
29 |
30 | // checks if the array.length is lower than the passed value
31 | array.min = function (min) {
32 | if (typeof min !== 'number') {
33 | throw new TypeError('array.min - min is not a number')
34 | }
35 | return toFunction(this, function () {
36 | if (value.length < $min$) {
37 | return false
38 | }
39 | }, { $min$: min })
40 | }
41 |
42 | // Makes writable the length object property
43 | Object.defineProperty(array, 'length', {
44 | writable: true
45 | })
46 | // checks if the array.length is the same if the passed value
47 | array.length = function (len) {
48 | if (typeof len !== 'number') {
49 | throw new TypeError('array.length - len is not a number')
50 | }
51 | return toFunction(this, function () {
52 | if (value.length !== $length$) {
53 | return false
54 | }
55 | }, { $length$: len })
56 | }
57 |
58 | // checks if the array value contains the passed value
59 | array.contains = function (containValue) {
60 | return toFunction(this, function () {
61 | if (value.indexOf($containValue$) === -1) {
62 | return false
63 | }
64 | }, { $containValue$: containValue })
65 | }
66 |
67 | // checks if every array item is valid using the function passed as parameter
68 | array.items = function (func) {
69 | if (typeof func !== 'function') {
70 | throw new TypeError('array.items parameter must be a function')
71 | }
72 | return toFunction(this, function () {
73 | const validate = $func$
74 | for (let i = 0, len = value.length; i < len; i++) {
75 | if (!validate(value[i])) {
76 | return false
77 | }
78 | }
79 | }, { $func$: func })
80 | }
81 |
82 | // Extends an array function
83 | array.extend = function (func) {
84 | return extend(this, func, toFunction)
85 | }
86 |
87 | const toFunction = buildToFunction(array)
88 | module.exports = array
89 |
--------------------------------------------------------------------------------
/lib/boolean.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* globals value */
4 |
5 | const buildToFunction = require('./common').toFunction
6 | const extend = require('./common').extend
7 |
8 | const boolean = function () {
9 | return toFunction(null, function () {
10 | if (typeof value !== 'boolean') {
11 | return false
12 | }
13 | })
14 | }
15 |
16 | // Extends a boolean function
17 | boolean.extend = function (func) {
18 | return extend(this, func, toFunction)
19 | }
20 |
21 | const toFunction = buildToFunction(boolean)
22 | module.exports = boolean
23 |
--------------------------------------------------------------------------------
/lib/common.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* eslint-disable no-new-func */
4 |
5 | const common = {
6 | toFunction: function (validatorObject) {
7 | if (typeof validatorObject !== 'function') {
8 | throw new TypeError('validatorObject is not a function')
9 | }
10 | return (context, validatorFunction, validatorParameters) => {
11 | // Error checking
12 | if (typeof context !== 'function' && context !== null) {
13 | throw new TypeError('context is not a function or null')
14 | }
15 | if (typeof validatorFunction !== 'function') {
16 | throw new TypeError('validatorFunction must be a function')
17 | }
18 | if (validatorParameters && typeof validatorParameters !== 'object') {
19 | throw new TypeError('validatorParameters must be an object')
20 | }
21 |
22 | // Returns an array with every line of the function
23 | // Here we remove the function declaration,
24 | // this works ONLY if there are not destructuring assignment as parameters.
25 | // Because of the lib design the validator function has never parameters,
26 | // so we can be "safe" about the following implementation.
27 | const linesOfCode = func => {
28 | func = func.toString()
29 | return func.substring(func.indexOf('{') + 1, func.lastIndexOf('}'))
30 | .split('\n')
31 | .filter(line => line.trim() !== '') // Removes empty lines
32 | }
33 |
34 | let code = ''
35 | // if the validator has already been defined
36 | if (context !== null) {
37 | let lines = linesOfCode(context)
38 | // Gets the number of spaces between
39 | // the beginning of the string and the first character
40 | let spaces = lines[0].search(/\S/)
41 | // Formats the indentation
42 | lines.forEach((line, index) => {
43 | if (index === lines.length - 1) return
44 | if (line.trim() === '{') spaces = line.search(/\S/)
45 | code += `
46 | ${line.slice(spaces)}`
47 | })
48 | // if is a new validator
49 | } else {
50 | // Function code
51 | code = `
52 | "use strict"
53 | `
54 | }
55 |
56 | code += `
57 | {`
58 | const lines = linesOfCode(validatorFunction)
59 | const spaces = lines[0].search(/\S/)
60 |
61 | lines.forEach(line => {
62 | for (let val in validatorParameters) {
63 | let value
64 | if (typeof validatorParameters[val] === 'string') {
65 | value = `'${validatorParameters[val]}'`
66 |
67 | // If the variable is an object (but not an instance of RegExp) we stringify it
68 | } else if (typeof validatorParameters[val] === 'object' && !(validatorParameters[val] instanceof RegExp)) {
69 | value = JSON.stringify(validatorParameters[val])
70 |
71 | // If the variable is a function
72 | } else if (typeof validatorParameters[val] === 'function') {
73 | value = validatorParameters[val].toString()
74 |
75 | // In all the other cases we add it 'as is' to the code
76 | } else {
77 | value = validatorParameters[val]
78 | }
79 | // Replace $varname$ with its value
80 | line = line.replace(new RegExp('\\' + val.substring(0, val.length - 1) + '\\$', 'g'), value)
81 | }
82 | code += `
83 | ${line.slice(spaces)}`
84 | })
85 | // Ends the block scope
86 | code += `
87 | };`
88 |
89 | code += `
90 | return true`
91 |
92 | // Appends all the validator functions to the newly generated function
93 | const func = new Function('value', code)
94 | Object.keys(validatorObject).forEach(val => {
95 | func[val] = validatorObject[val]
96 | })
97 |
98 | // Fix for .length property
99 | Object.defineProperty(func, 'length', {
100 | writable: true
101 | })
102 | if (typeof validatorObject.length === 'function') {
103 | func.length = validatorObject.length
104 | }
105 |
106 | return func
107 | }
108 | },
109 |
110 | or: function () {
111 | const functions = Array.prototype.slice.call(arguments)
112 | let code = ` "use strict"
113 | `
114 | let returnCode = `
115 | return`
116 |
117 | functions.forEach((func, index) => {
118 | if (typeof func !== 'function') {
119 | throw new Error('tyval.or, parameters must be functions')
120 | }
121 | // Stringify every validator function in the code
122 | code += `
123 | const validate${index} = ${func.toString()}`
124 | // Call every declared function
125 | returnCode += ` validate${index}(orValue)`
126 | if (index < functions.length - 1) {
127 | returnCode += ' ||'
128 | }
129 | })
130 |
131 | // Declares all the validator functions
132 | // and use them with closures
133 | code += `
134 | function orify (orValue) {${returnCode}
135 | }
136 | return orify`
137 | return new Function(code)()
138 | },
139 |
140 | extend: function (tyvalValidator, func, toFunction) {
141 | // Error checking
142 | if (typeof tyvalValidator !== 'function') {
143 | throw new TypeError('tyvalValidator is not a function')
144 | }
145 | if (typeof func !== 'function') {
146 | throw new TypeError('func is not a function')
147 | }
148 | if (typeof toFunction !== 'function') {
149 | throw new TypeError('toFunction is not a function')
150 | }
151 |
152 | // Thanks to: https://davidwalsh.name/javascript-arguments
153 | // gets the name of the arguments of a function
154 | const getArgs = func => {
155 | // First match everything inside the function argument parens.
156 | let args = func.toString().match(/function\s.*?\(([^)]*)\)/)[1]
157 | // Split the arguments string into an array comma delimited.
158 | return args.split(',').map(arg => {
159 | // Ensure no inline comments are parsed and trim the whitespace.
160 | return arg.replace(/\/\*.*\*\//, '').trim()
161 | }).filter(arg => {
162 | // Ensure no undefined values are added.
163 | return arg
164 | })
165 | }
166 |
167 | // Gets the parameters name
168 | const parametersName = getArgs(func)
169 |
170 | // Extends the passed tyval validator with a new function
171 | tyvalValidator[func.name] = function () {
172 | // gets the parameters passed as arguments
173 | const parametersValue = Array.prototype.slice.call(arguments)
174 | if (parametersName.length !== parametersValue.length) {
175 | throw new Error('The length of parametersName and parametersValue do not coincide')
176 | }
177 |
178 | // Instantiate the parameters object
179 | const parameters = {}
180 | for (let i = 0; i < parametersName.length; i++) {
181 | // Adds the parameters name: value
182 | parameters['$' + parametersName[i] + '$'] = parametersValue[i]
183 | }
184 |
185 | return toFunction(this, func, parameters)
186 | }
187 | }
188 | }
189 |
190 | module.exports = common
191 |
--------------------------------------------------------------------------------
/lib/date.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* globals value, $newDate$ */
4 |
5 | const buildToFunction = require('./common').toFunction
6 | const extend = require('./common').extend
7 |
8 | const date = function () {
9 | return toFunction(null, function () {
10 | if (!(value instanceof Date)) {
11 | return false
12 | }
13 | })
14 | }
15 |
16 | // checks if the date value is lower than the passed date
17 | date.lower = function (d) {
18 | return toFunction(this, function () {
19 | if (value.getTime() >= $newDate$) {
20 | return false
21 | }
22 | }, { $newDate$: d.getTime() })
23 | }
24 |
25 | // checks if the date value is higher than the passed date
26 | date.higher = function (d) {
27 | return toFunction(this, function () {
28 | if (value.getTime() <= $newDate$) {
29 | return false
30 | }
31 | }, { $newDate$: d.getTime() })
32 | }
33 |
34 | // Extends a date function
35 | date.extend = function (func) {
36 | return extend(this, func, toFunction)
37 | }
38 |
39 | const toFunction = buildToFunction(date)
40 | module.exports = date
41 |
--------------------------------------------------------------------------------
/lib/error.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* globals value, $message$ */
4 |
5 | const buildToFunction = require('./common').toFunction
6 | const extend = require('./common').extend
7 |
8 | // checks if the value is an instance of Error
9 | const error = function () {
10 | return toFunction(null, function () {
11 | if (!(value instanceof Error)) {
12 | return false
13 | }
14 | })
15 | }
16 |
17 | // checks if the value is an instance of RangeError
18 | error.RangeError = function () {
19 | return toFunction(this, function () {
20 | if (!(value instanceof RangeError)) {
21 | return false
22 | }
23 | })
24 | }
25 |
26 | // checks if the value is an instance of ReferenceError
27 | error.ReferenceError = function () {
28 | return toFunction(this, function () {
29 | if (!(value instanceof ReferenceError)) {
30 | return false
31 | }
32 | })
33 | }
34 |
35 | // checks if the value is an instance of SyntaxError
36 | error.SyntaxError = function () {
37 | return toFunction(this, function () {
38 | if (!(value instanceof SyntaxError)) {
39 | return false
40 | }
41 | })
42 | }
43 |
44 | // checks if the value is an instance of TypeError
45 | error.TypeError = function () {
46 | return toFunction(this, function () {
47 | if (!(value instanceof TypeError)) {
48 | return false
49 | }
50 | })
51 | }
52 |
53 | // checks if the error message is the same as the given parameter
54 | error.message = function (message) {
55 | if (typeof message !== 'string') {
56 | throw new Error('error message must be a string')
57 | }
58 | return toFunction(this, function () {
59 | if (value.message !== $message$) {
60 | return false
61 | }
62 | }, { $message$: message })
63 | }
64 |
65 | // Extends an object function
66 | error.extend = function (func) {
67 | return extend(this, func, toFunction)
68 | }
69 |
70 | const toFunction = buildToFunction(error)
71 | module.exports = error
72 |
--------------------------------------------------------------------------------
/lib/number.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* globals value */
4 | /* eslint-disable no-undef */
5 |
6 | const buildToFunction = require('./common').toFunction
7 | const extend = require('./common').extend
8 |
9 | // checks if the value is a number
10 | const number = function () {
11 | return toFunction(null, function () {
12 | if (typeof value !== 'number') {
13 | return false
14 | }
15 | })
16 | }
17 |
18 | // checks if the number is lower than the passed value
19 | number.max = function (max) {
20 | if (typeof max !== 'number') {
21 | throw new TypeError('number.max - max is not a number')
22 | }
23 | return toFunction(this, function () {
24 | if (value > $max$) {
25 | return false
26 | }
27 | }, { $max$: max })
28 | }
29 |
30 | // checks if the number is higher than the passed value
31 | number.min = function (min) {
32 | if (typeof min !== 'number') {
33 | throw new TypeError('number.min - min is not a number')
34 | }
35 | return toFunction(this, function () {
36 | if (value < $min$) {
37 | return false
38 | }
39 | }, { $min$: min })
40 | }
41 |
42 | // checks if the value is a positive number
43 | number.positive = function () {
44 | return toFunction(this, function () {
45 | if (value < 0) {
46 | return false
47 | }
48 | })
49 | }
50 |
51 | // checks if the value is a negative number
52 | number.negative = function () {
53 | return toFunction(this, function () {
54 | if (value > 0) {
55 | return false
56 | }
57 | })
58 | }
59 |
60 | // checks if the value is an Integer
61 | number.integer = function () {
62 | // Thanks to https://github.com/mafintosh/is-my-json-valid
63 | return toFunction(this, function () {
64 | if (!(Math.floor(value) === value || value > 9007199254740992 || value < -9007199254740992)) {
65 | return false
66 | }
67 | })
68 | }
69 |
70 | // checks if the value is a Float
71 | number.float = function () {
72 | // Thanks to https://github.com/mafintosh/is-my-json-valid
73 | return toFunction(this, function () {
74 | if (Math.floor(value) === value || value > 9007199254740992 || value < -9007199254740992) {
75 | return false
76 | }
77 | })
78 | }
79 |
80 | // checks if the value is a safe integer
81 | number.safeInteger = function () {
82 | return toFunction(this, function () {
83 | if (value > 9007199254740991 || value < -9007199254740991) {
84 | return false
85 | }
86 | })
87 | }
88 |
89 | // checks if the value is a finite number
90 | number.finite = function () {
91 | return toFunction(this, function () {
92 | if (!Number.isFinite(value)) {
93 | return false
94 | }
95 | })
96 | }
97 |
98 | // checks if the value if a multiple of the passed value
99 | number.multiple = function (mult) {
100 | if (typeof mult !== 'number') {
101 | throw new TypeError('number.multiple - mult is not a number')
102 | }
103 | return toFunction(this, function () {
104 | if (value % $multiple$ !== 0) {
105 | return false
106 | }
107 | }, { $multiple$: mult })
108 | }
109 |
110 | // checks if the value is not NaN
111 | number.notNaN = function () {
112 | return toFunction(this, function () {
113 | if (Number.isNaN(value)) {
114 | return false
115 | }
116 | })
117 | }
118 |
119 | // checks if the number is a valid network port number
120 | number.port = function (options) {
121 | options = options || {}
122 | return toFunction(this, function () {
123 | if (value > 65535 || value < ($reserved$ ? 1024 : 0)) {
124 | return false
125 | }
126 | }, { $reserved$: options.reserved || false })
127 | }
128 |
129 | // Extends a number function
130 | number.extend = function (func) {
131 | return extend(this, func, toFunction)
132 | }
133 |
134 | const toFunction = buildToFunction(number)
135 | module.exports = number
136 |
--------------------------------------------------------------------------------
/lib/object.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* globals value */
4 | /* eslint-disable no-undef */
5 |
6 | const buildToFunction = require('./common').toFunction
7 | const extend = require('./common').extend
8 |
9 | const object = function () {
10 | return toFunction(null, function () {
11 | if (typeof value !== 'object') {
12 | return false
13 | }
14 | })
15 | }
16 |
17 | // checks if the value object is empty
18 | object.empty = function () {
19 | return toFunction(this, function () {
20 | if (Object.keys(value).length > 0) {
21 | return false
22 | }
23 | })
24 | }
25 |
26 | // checks if the value is not null (because typeof null = 'object')
27 | object.notNull = function () {
28 | return toFunction(this, function () {
29 | if (value === null) {
30 | return false
31 | }
32 | })
33 | }
34 |
35 | // checks if the value is not an array (because typeof [] = 'object')
36 | object.notArray = function notArray () {
37 | return toFunction(this, function () {
38 | if (Array.isArray(value)) {
39 | return false
40 | }
41 | })
42 | }
43 |
44 | // checks if the value is not a Date (because of typeof new Date() = 'object')
45 | object.notDate = function notDate () {
46 | return toFunction(this, function () {
47 | if (value instanceof Date) {
48 | return false
49 | }
50 | })
51 | }
52 |
53 | // checks if the value is not a RegExp (becaus of typeof new RegExp() = 'object')
54 | object.notRegExp = function notRegExp () {
55 | return toFunction(this, function () {
56 | if (value instanceof RegExp) {
57 | return false
58 | }
59 | })
60 | }
61 |
62 | // checks if the value has the passed key
63 | // if fast is true the perf gets a ~10x speed
64 | object.has = function has (haskey, options) {
65 | if (typeof haskey !== 'string') {
66 | throw new TypeError('object.has - haskey is not a string')
67 | }
68 | options = options || {}
69 | if (options.fast) {
70 | return toFunction(this, function () {
71 | if (value[$haskey$] === undefined) {
72 | return false
73 | }
74 | }, { $haskey$: haskey })
75 | } else {
76 | return toFunction(this, function () {
77 | if (!(value.hasOwnProperty($haskey$))) {
78 | return false
79 | }
80 | }, { $haskey$: haskey })
81 | }
82 | }
83 |
84 | // checks if the value has not the passed key
85 | // if fast is true the perf gets a ~4x speed
86 | object.hasNot = function (hasnotkey, options) {
87 | if (typeof hasnotkey !== 'string') {
88 | throw new TypeError('object.hasNot - hasnotkey is not a string')
89 | }
90 | options = options || {}
91 | if (options.fast) {
92 | return toFunction(this, function () {
93 | if (value[$hasnotkey$] !== undefined) {
94 | return false
95 | }
96 | }, { $hasnotkey$: hasnotkey })
97 | } else {
98 | return toFunction(this, function () {
99 | if (value.hasOwnProperty($hasnotkey$)) {
100 | return false
101 | }
102 | }, { $hasnotkey$: hasnotkey })
103 | }
104 | }
105 |
106 | // Extends an object function
107 | object.extend = function (func) {
108 | return extend(this, func, toFunction)
109 | }
110 |
111 | const toFunction = buildToFunction(object)
112 | module.exports = object
113 |
--------------------------------------------------------------------------------
/lib/string.js:
--------------------------------------------------------------------------------
1 | 'use string'
2 |
3 | /* globals value */
4 | /* eslint-disable no-native-reassign, no-undef */
5 |
6 | const buildToFunction = require('./common').toFunction
7 | const extend = require('./common').extend
8 |
9 | // checks if the value is a string
10 | const string = function () {
11 | return toFunction(null, function () {
12 | if (typeof value !== 'string') {
13 | return false
14 | }
15 | })
16 | }
17 |
18 | // checks if the string is alphanumberic
19 | string.alphanum = function () {
20 | return toFunction(this, function () {
21 | const reg = /((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+[0-9a-z]+$/i
22 | if (!(reg.test(value))) {
23 | return false
24 | }
25 | })
26 | }
27 |
28 | // Tests the regex passed as input
29 | string.regex = function (reg) {
30 | if (!(reg instanceof RegExp)) {
31 | throw new TypeError('string.regex - reg is not a RegExp')
32 | }
33 | return toFunction(this, function () {
34 | const reg = $reg$
35 | if (!(reg.test(value))) {
36 | return false
37 | }
38 | }, { $reg$: reg })
39 | }
40 |
41 | // checks if the string.length is lower than the passed max value
42 | string.max = function (max) {
43 | if (typeof max !== 'number') {
44 | throw new TypeError('string.max - max is not a number')
45 | }
46 | return toFunction(this, function () {
47 | if (value.length > $max$) {
48 | return false
49 | }
50 | }, { $max$: max })
51 | }
52 |
53 | // checks if the string.length is higher than the passed value
54 | string.min = function (min) {
55 | if (typeof min !== 'number') {
56 | throw new TypeError('string.min - min is not a number')
57 | }
58 | return toFunction(this, function () {
59 | if (value.length < $min$) {
60 | return false
61 | }
62 | }, { $min$: min })
63 | }
64 |
65 | // Makes writable the length object property
66 | Object.defineProperty(string, 'length', {
67 | writable: true
68 | })
69 | // checks if the string.length is the same than the passed value
70 | string.length = function (len) {
71 | if (typeof len !== 'number') {
72 | throw new TypeError('string.length - len is not a number')
73 | }
74 | return toFunction(this, function () {
75 | if (value.length !== $length$) {
76 | return false
77 | }
78 | }, { $length$: len })
79 | }
80 |
81 | // checks if the value is a valid mail string
82 | string.mail = function () {
83 | // Thanks to: https://stackoverflow.com/questions/46155/validate-email-address-in-javascript
84 | return toFunction(this, function () {
85 | const mailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
86 | if (!(mailReg.test(value))) {
87 | return false
88 | }
89 | })
90 | }
91 |
92 | // checks if the value is a valid ipv4 string
93 | string.ipv4 = function () {
94 | return toFunction(this, function () {
95 | const ipReg = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
96 | if (!(ipReg.test(value))) {
97 | return false
98 | }
99 | })
100 | }
101 |
102 | // checks if the value is a valid ipv6 string
103 | string.ipv6 = function () {
104 | // Thanks to: https://community.helpsystems.com/forums/intermapper/miscellaneous-topics/5acc4fcf-fa83-e511-80cf-0050568460e4
105 | return toFunction(this, function () {
106 | const ipReg = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
107 | if (!(ipReg.test(value))) {
108 | return false
109 | }
110 | })
111 | }
112 |
113 | // checks if the value is a valid base64 string
114 | string.base64 = function () {
115 | return toFunction(this, function () {
116 | const base64Reg = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/
117 | if (!(base64Reg.test(value))) {
118 | return false
119 | }
120 | })
121 | }
122 |
123 | // checks if the value is a valid JSON
124 | string.JSON = function () {
125 | return toFunction(this, function () {
126 | try {
127 | JSON.parse(value)
128 | } catch (e) {
129 | return false
130 | }
131 | })
132 | }
133 |
134 | // checks if the value is a valid uuid string
135 | string.uuid = function () {
136 | return toFunction(this, function () {
137 | const uuidReg = /[a-f0-9]{8}-?[a-f0-9]{4}-?[1-5][a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}/i
138 | if (!(uuidReg.test(value))) {
139 | return false
140 | }
141 | })
142 | }
143 |
144 | // checks if the value is a valid MAC address
145 | string.MAC = function () {
146 | return toFunction(this, function () {
147 | const macReg = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/
148 | if (!(macReg.test(value))) {
149 | return false
150 | }
151 | })
152 | }
153 |
154 | // checks if the value is a valid md5 string
155 | string.md5 = function () {
156 | return toFunction(this, function () {
157 | const md5Reg = /^[a-f0-9]{32}$/
158 | if (!(md5Reg.test(value))) {
159 | return false
160 | }
161 | })
162 | }
163 |
164 | // checks if the value corresponds to the card code selected
165 | string.card = function (cardType) {
166 | if (typeof cardType !== 'string') {
167 | throw new Error('cardType must be a string')
168 | }
169 | // Thanks to: https://github.com/DylanPiercey/the
170 | const cards = {
171 | jcb: /^(?:2131|1800|35\d{3})\d{11}$/,
172 | visa: /^4\d{12}(?:\d{3})?$/,
173 | discover: /^6(?:011|5\d{2})\d{12}$/,
174 | dinersclub: /^3(?:0[0-5]|[68]\d)\d{11}$/,
175 | mastercard: /^5[1-5]\d{14}$/,
176 | americanexpress: /^3[47]\d{13}$/
177 | }
178 | if (!cards[cardType]) {
179 | throw new Error(cardType + ' card is not supported')
180 | }
181 | return toFunction(this, function () {
182 | if (!($reg$.test(value))) {
183 | return false
184 | }
185 | }, { $reg$: cards[cardType] })
186 | }
187 |
188 | // Extends a string function
189 | string.extend = function (func) {
190 | return extend(this, func, toFunction)
191 | }
192 |
193 | const toFunction = buildToFunction(string)
194 | module.exports = string
195 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tyval",
3 | "version": "4.0.0",
4 | "description": "Fast and extensible validator for JavaScript",
5 | "main": "tyval.js",
6 | "scripts": {
7 | "bench": "npm run pretest && node bench/bench.js",
8 | "pretest": "standard",
9 | "test": "tap test/*.js",
10 | "test:all": "./test/test-runner.sh",
11 | "browser": "node build-browser.js"
12 | },
13 | "keywords": [
14 | "fast",
15 | "validator",
16 | "validation",
17 | "extensible",
18 | "composable",
19 | "type",
20 | "variable",
21 | "check",
22 | "value"
23 | ],
24 | "author": "Tomas Della Vedova - @delvedor (http://delved.org)",
25 | "license": "MIT",
26 | "repository": {
27 | "type": "git",
28 | "url": "git+https://github.com/delvedor/Tyval.git"
29 | },
30 | "bugs": {
31 | "url": "https://github.com/delvedor/Tyval/issues"
32 | },
33 | "homepage": "https://github.com/delvedor/Tyval#readme",
34 | "engines": {
35 | "node": ">=4.0.0"
36 | },
37 | "devDependencies": {
38 | "babel-preset-es2015": "^6.16.0",
39 | "babelify": "^7.3.0",
40 | "benchmark": "^2.1.1",
41 | "browserify": "^13.1.0",
42 | "chalk": "^1.1.3",
43 | "is-my-json-valid": "^2.15.0",
44 | "joi": "^9.1.1",
45 | "replacestream": "^4.0.2",
46 | "self-stream": "^1.1.1",
47 | "standard": "^8.3.0",
48 | "tap": "^7.1.2",
49 | "uglify-js": "^2.7.3",
50 | "validate.js": "^0.10.0"
51 | },
52 | "dependencies": {}
53 | }
54 |
--------------------------------------------------------------------------------
/test/array.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const tap = require('tap')
4 | const test = tap.test
5 | const tyval = require('../tyval')
6 |
7 | test('array', (t) => {
8 | t.plan(4)
9 | t.is(typeof tyval.array, 'function')
10 | let arr = tyval.array()
11 | t.is(typeof arr, 'function')
12 | t.true(arr([]))
13 | t.false(arr('test'))
14 | })
15 |
16 | test('array.max', (t) => {
17 | t.plan(4)
18 | t.is(typeof tyval.array.max, 'function')
19 | let max = tyval.array().max(10)
20 | t.is(typeof max, 'function')
21 | t.true(max([1, 2, 3]))
22 | t.false(max([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]))
23 | })
24 |
25 | test('array.min', (t) => {
26 | t.plan(4)
27 | t.is(typeof tyval.array.min, 'function')
28 | let min = tyval.array().min(3)
29 | t.is(typeof min, 'function')
30 | t.true(min([1, 2, 3, 4]))
31 | t.false(min([]))
32 | })
33 |
34 | test('array.length', (t) => {
35 | t.plan(4)
36 | t.is(typeof tyval.array.length, 'function')
37 | let len = tyval.array().length(3)
38 | t.is(typeof len, 'function')
39 | t.true(len([1, 2, 3]))
40 | t.false(len([1, 2]))
41 | })
42 |
43 | test('arrayTest', (t) => {
44 | t.plan(4)
45 | let arrayTest = tyval.array().max(10).min(2)
46 | t.is(typeof arrayTest, 'function')
47 | t.true(arrayTest([1, 2, 3]))
48 | t.false(arrayTest([1]))
49 | t.false(arrayTest({}))
50 | })
51 |
52 | /* eslint-disable no-undef */
53 | test('array.extend', (t) => {
54 | t.plan(4)
55 | tyval.array.extend(function empty () {
56 | if (value.length !== 0) {
57 | return false
58 | }
59 | })
60 | t.is(typeof tyval.array.empty, 'function')
61 | let empty = tyval.array().empty()
62 | t.is(typeof empty, 'function')
63 | t.true(empty([]))
64 | t.false(empty([1]))
65 | })
66 | /* eslint-disable no-undef */
67 |
68 | test('array.contains', (t) => {
69 | t.plan(4)
70 | t.is(typeof tyval.array.contains, 'function')
71 | let contains = tyval.array().contains(3)
72 | t.is(typeof contains, 'function')
73 | t.true(contains([1, 2, 3]))
74 | t.false(contains([1, 2]))
75 | })
76 |
77 | test('array.items', (t) => {
78 | t.plan(4)
79 | t.is(typeof tyval.array.items, 'function')
80 | let item = tyval.string()
81 | let items = tyval.array().items(item)
82 | t.is(typeof items, 'function')
83 | t.true(items(['a', 'b', 'c']))
84 | t.false(items([1, 'a', null]))
85 | })
86 |
--------------------------------------------------------------------------------
/test/boolean.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const tap = require('tap')
4 | const test = tap.test
5 | const tyval = require('../tyval')
6 |
7 | test('boolean', (t) => {
8 | t.plan(4)
9 | t.is(typeof tyval.boolean, 'function')
10 | let bool = tyval.boolean()
11 | t.is(typeof bool, 'function')
12 | t.true(bool(true))
13 | t.false(bool('test'))
14 | })
15 |
16 |
--------------------------------------------------------------------------------
/test/date.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const tap = require('tap')
4 | const test = tap.test
5 | const tyval = require('../tyval')
6 |
7 | test('date', (t) => {
8 | t.plan(4)
9 | t.is(typeof tyval.date, 'function')
10 | let isDate = tyval.date()
11 | t.is(typeof isDate, 'function')
12 | t.true(isDate(new Date()))
13 | t.false(isDate('2016-06-03T13:45:53.225Z'))
14 | })
15 |
16 | test('date.lower', (t) => {
17 | t.plan(4)
18 | t.is(typeof tyval.date.lower, 'function')
19 | let l = new Date()
20 | while (l.getTime() === new Date().getTime()) {}
21 | let h = new Date()
22 | let date = tyval.date().lower(h)
23 | t.is(typeof date, 'function')
24 | t.true(date(l))
25 | t.false(date(h))
26 | })
27 |
28 | test('date.higher', (t) => {
29 | t.plan(4)
30 | t.is(typeof tyval.date.lower, 'function')
31 | let l = new Date()
32 | while (l.getTime() === new Date().getTime()) {}
33 | let h = new Date()
34 | let date = tyval.date().higher(l)
35 | t.is(typeof date, 'function')
36 | t.true(date(h))
37 | t.false(date(l))
38 | })
39 |
--------------------------------------------------------------------------------
/test/error.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const tap = require('tap')
4 | const test = tap.test
5 | const tyval = require('../tyval')
6 |
7 | test('error', (t) => {
8 | t.plan(4)
9 | t.is(typeof tyval.error, 'function')
10 | let err = tyval.error()
11 | t.is(typeof err, 'function')
12 | t.true(err(new Error()))
13 | t.false(err([]))
14 | })
15 |
16 | test('error.RangeError', (t) => {
17 | t.plan(4)
18 | t.is(typeof tyval.error.RangeError, 'function')
19 | let err = tyval.error().RangeError()
20 | t.is(typeof err, 'function')
21 | t.true(err(new RangeError()))
22 | t.false(err(new Error()))
23 | })
24 |
25 | test('error.ReferenceError', (t) => {
26 | t.plan(4)
27 | t.is(typeof tyval.error.ReferenceError, 'function')
28 | let err = tyval.error().ReferenceError()
29 | t.is(typeof err, 'function')
30 | t.true(err(new ReferenceError()))
31 | t.false(err(new Error()))
32 | })
33 |
34 | test('error.SyntaxError', (t) => {
35 | t.plan(4)
36 | t.is(typeof tyval.error.SyntaxError, 'function')
37 | let err = tyval.error().SyntaxError()
38 | t.is(typeof err, 'function')
39 | t.true(err(new SyntaxError()))
40 | t.false(err(new Error()))
41 | })
42 |
43 | test('error.TypeError', (t) => {
44 | t.plan(4)
45 | t.is(typeof tyval.error.TypeError, 'function')
46 | let err = tyval.error().TypeError()
47 | t.is(typeof err, 'function')
48 | t.true(err(new TypeError()))
49 | t.false(err(new Error()))
50 | })
51 |
52 | test('error.message', (t) => {
53 | t.plan(4)
54 | t.is(typeof tyval.error.message, 'function')
55 | let err = tyval.error().message('some error')
56 | t.is(typeof err, 'function')
57 | t.true(err(new Error('some error')))
58 | t.false(err(new Error('other error')))
59 | })
60 |
--------------------------------------------------------------------------------
/test/number.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const tap = require('tap')
4 | const test = tap.test
5 | const tyval = require('../tyval')
6 |
7 | test('number', (t) => {
8 | t.plan(4)
9 | t.is(typeof tyval.number, 'function')
10 | let num = tyval.number()
11 | t.is(typeof num, 'function')
12 | t.true(num(1))
13 | t.false(num('test'))
14 | })
15 |
16 | test('number.max', (t) => {
17 | t.plan(4)
18 | t.is(typeof tyval.number.max, 'function')
19 | let max = tyval.number().max(10)
20 | t.is(typeof max, 'function')
21 | t.true(max(5))
22 | t.false(max(15))
23 | })
24 |
25 | test('number.min', (t) => {
26 | t.plan(4)
27 | t.is(typeof tyval.number.min, 'function')
28 | let min = tyval.number().min(4)
29 | t.is(typeof min, 'function')
30 | t.true(min(5))
31 | t.false(min(3))
32 | })
33 |
34 | test('number.positive', (t) => {
35 | t.plan(4)
36 | t.is(typeof tyval.number.positive, 'function')
37 | let pos = tyval.number().positive()
38 | t.is(typeof pos, 'function')
39 | t.true(pos(5))
40 | t.false(pos(-5))
41 | })
42 |
43 | test('number.negative', (t) => {
44 | t.plan(4)
45 | t.is(typeof tyval.number.negative, 'function')
46 | let neg = tyval.number().negative()
47 | t.is(typeof neg, 'function')
48 | t.true(neg(-5))
49 | t.false(neg(5))
50 | })
51 |
52 | test('number.integer', (t) => {
53 | t.plan(4)
54 | t.is(typeof tyval.number.integer, 'function')
55 | let int = tyval.number().integer()
56 | t.is(typeof int, 'function')
57 | t.true(int(1))
58 | t.false(int(1.1))
59 | })
60 |
61 | test('number.float', (t) => {
62 | t.plan(4)
63 | t.is(typeof tyval.number.float, 'function')
64 | let float = tyval.number().float()
65 | t.is(typeof float, 'function')
66 | t.true(float(1.1))
67 | t.false(float(1))
68 | })
69 |
70 | test('number.safeInteger', (t) => {
71 | t.plan(4)
72 | t.is(typeof tyval.number.safeInteger, 'function')
73 | let safe = tyval.number().safeInteger()
74 | t.is(typeof safe, 'function')
75 | t.true(safe(1))
76 | t.false(safe(Number.MAX_SAFE_INTEGER + 1))
77 | })
78 |
79 | test('number.finite', (t) => {
80 | t.plan(4)
81 | t.is(typeof tyval.number.finite, 'function')
82 | let fin = tyval.number().finite()
83 | t.is(typeof fin, 'function')
84 | t.true(fin(1))
85 | t.false(fin(Number.POSITIVE_INFINITY))
86 | })
87 |
88 | test('number.multiple', (t) => {
89 | t.plan(4)
90 | t.is(typeof tyval.number.multiple, 'function')
91 | let mul2 = tyval.number().multiple(2)
92 | t.is(typeof mul2, 'function')
93 | t.true(mul2(10))
94 | t.false(mul2(3))
95 | })
96 |
97 | test('numTest', (t) => {
98 | t.plan(5)
99 | let numTest = tyval.number().min(-5).max(10).integer().finite().safeInteger()
100 | t.is(typeof numTest, 'function')
101 | t.true(numTest(5))
102 | t.false(numTest(15))
103 | t.false(numTest('15'))
104 | t.false(numTest(NaN))
105 | })
106 |
107 | /* eslint-disable no-undef */
108 | test('number.extend', (t) => {
109 | t.plan(4)
110 | tyval.number.extend(function isZero () {
111 | if (value !== 0) {
112 | return false
113 | }
114 | })
115 | t.is(typeof tyval.number.isZero, 'function')
116 | let zero = tyval.number().isZero()
117 | t.is(typeof zero, 'function')
118 | t.true(zero(0))
119 | t.false(zero(1))
120 | })
121 | /* eslint-disable no-undef */
122 |
123 | test('number.notNaN', (t) => {
124 | t.plan(4)
125 | t.is(typeof tyval.number.notNaN, 'function')
126 | let n = tyval.number().notNaN()
127 | t.is(typeof n, 'function')
128 | t.true(n(1))
129 | t.false(n(NaN))
130 | })
131 |
132 | test('number.port', (t) => {
133 | t.plan(8)
134 | t.is(typeof tyval.number.port, 'function')
135 | let port = tyval.number().port()
136 | let portReserved = tyval.number().port({ reserved: true })
137 | t.is(typeof port, 'function')
138 | t.is(typeof portReserved, 'function')
139 | t.true(port(1024))
140 | t.false(port(-10))
141 | t.false(port(70000))
142 | t.true(portReserved(1025))
143 | t.false(portReserved(1000))
144 | })
145 |
--------------------------------------------------------------------------------
/test/object.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const tap = require('tap')
4 | const test = tap.test
5 | const tyval = require('../tyval')
6 |
7 | test('object', (t) => {
8 | t.plan(4)
9 | t.is(typeof tyval.object, 'function')
10 | let obj = tyval.object()
11 | t.is(typeof obj, 'function')
12 | t.true(obj({}))
13 | t.false(obj('test'))
14 | })
15 |
16 | test('object.empty', (t) => {
17 | t.plan(4)
18 | t.is(typeof tyval.object.empty, 'function')
19 | let empty = tyval.object().empty()
20 | t.is(typeof empty, 'function')
21 | t.true(empty({}))
22 | t.false(empty({key: 'value'}))
23 | })
24 |
25 | test('object.notNull', (t) => {
26 | t.plan(4)
27 | t.is(typeof tyval.object.notNull, 'function')
28 | let n = tyval.object().notNull()
29 | t.is(typeof n, 'function')
30 | t.true(n({}))
31 | t.false(n(null))
32 | })
33 |
34 | test('object.notArray', (t) => {
35 | t.plan(4)
36 | t.is(typeof tyval.object.notArray, 'function')
37 | let a = tyval.object().notArray()
38 | t.is(typeof a, 'function')
39 | t.true(a({}))
40 | t.false(a([]))
41 | })
42 |
43 | test('object.notDate', (t) => {
44 | t.plan(4)
45 | t.is(typeof tyval.object.notDate, 'function')
46 | let n = tyval.object().notDate()
47 | t.is(typeof n, 'function')
48 | t.true(n({}))
49 | t.false(n(new Date()))
50 | })
51 |
52 | test('object.notRegExp', (t) => {
53 | t.plan(4)
54 | t.is(typeof tyval.object.notRegExp, 'function')
55 | let n = tyval.object().notRegExp()
56 | t.is(typeof n, 'function')
57 | t.true(n({}))
58 | t.false(n(new RegExp()))
59 | })
60 |
61 | test('object.has', (t) => {
62 | t.plan(4)
63 | t.is(typeof tyval.object.has, 'function')
64 | let has = tyval.object().has('test')
65 | t.is(typeof has, 'function')
66 | t.true(has({test: ''}))
67 | t.false(has({nope: ''}))
68 | })
69 |
70 | test('object.has fast', (t) => {
71 | t.plan(5)
72 | t.is(typeof tyval.object.has, 'function')
73 | let has = tyval.object().has('test', { fast: true })
74 | t.is(typeof has, 'function')
75 | t.true(has({test: ''}))
76 | t.false(has({nope: ''}))
77 | t.false(has({test: undefined}))
78 | })
79 |
80 | test('object.hasNot', (t) => {
81 | t.plan(4)
82 | t.is(typeof tyval.object.hasNot, 'function')
83 | let hasNot = tyval.object().hasNot('test')
84 | t.is(typeof hasNot, 'function')
85 | t.true(hasNot({nope: ''}))
86 | t.false(hasNot({test: ''}))
87 | })
88 |
89 | test('object.hasNot fast', (t) => {
90 | t.plan(5)
91 | t.is(typeof tyval.object.hasNot, 'function')
92 | let hasNot = tyval.object().hasNot('test', { fast: true })
93 | t.is(typeof hasNot, 'function')
94 | t.true(hasNot({nope: ''}))
95 | t.false(hasNot({test: ''}))
96 | t.true(hasNot({test: undefined}))
97 | })
98 |
99 | test('object.has - multiple', (t) => {
100 | t.plan(4)
101 | t.is(typeof tyval.object.has, 'function')
102 | let has = tyval.object().has('test').has('key')
103 | t.is(typeof has, 'function')
104 | t.true(has({test: 1, key: 2}))
105 | t.false(has({test: 1, nope: 2}))
106 | })
107 |
108 | test('object.hasNot - multiple', (t) => {
109 | t.plan(4)
110 | t.is(typeof tyval.object.hasNot, 'function')
111 | let hasNot = tyval.object().hasNot('test').hasNot('key')
112 | t.is(typeof hasNot, 'function')
113 | t.true(hasNot({nil: 1, nope: 2}))
114 | t.false(hasNot({test: 1, key: 2}))
115 | })
116 |
117 | test('object.has - object.hasNot', (t) => {
118 | t.plan(4)
119 | t.is(typeof tyval.object.hasNot, 'function')
120 | let key = tyval.object().has('test').hasNot('key')
121 | t.is(typeof key, 'function')
122 | t.true(key({test: 1, nope: 2}))
123 | t.false(key({test: 1, key: 2}))
124 | })
125 |
--------------------------------------------------------------------------------
/test/string.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const tap = require('tap')
4 | const test = tap.test
5 | const tyval = require('../tyval')
6 |
7 | test('string', (t) => {
8 | t.plan(4)
9 | t.is(typeof tyval.string, 'function')
10 | let str = tyval.string()
11 | t.is(typeof str, 'function')
12 | t.true(str('test'))
13 | t.false(str(1))
14 | })
15 |
16 | test('string.alphanum', (t) => {
17 | t.plan(5)
18 | t.is(typeof tyval.string.alphanum, 'function')
19 | let alp = tyval.string().alphanum()
20 | t.is(typeof alp, 'function')
21 | t.true(alp('abcd1234'))
22 | t.false(alp('abcd'))
23 | t.false(alp('123'))
24 | })
25 |
26 | test('string.regex', (t) => {
27 | t.plan(5)
28 | t.is(typeof tyval.string.regex, 'function')
29 | let regex = tyval.string().regex(/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+[0-9a-z]+$/i)
30 | t.is(typeof regex, 'function')
31 | t.true(regex('abcd1234'))
32 | t.false(regex('abcd'))
33 | t.false(regex('123'))
34 | })
35 |
36 | test('string.max', (t) => {
37 | t.plan(4)
38 | t.is(typeof tyval.string.max, 'function')
39 | let max = tyval.string().max(10)
40 | t.is(typeof max, 'function')
41 | t.true(max('test'))
42 | t.false(max('testtesttest'))
43 | })
44 |
45 | test('string.min', (t) => {
46 | t.plan(4)
47 | t.is(typeof tyval.string.min, 'function')
48 | let min = tyval.string().min(3)
49 | t.is(typeof min, 'function')
50 | t.true(min('test'))
51 | t.false(min('no'))
52 | })
53 |
54 | test('string.length', (t) => {
55 | t.plan(4)
56 | t.is(typeof tyval.string.length, 'function')
57 | let len = tyval.string().length(4)
58 | t.is(typeof len, 'function')
59 | t.true(len('test'))
60 | t.false(len('!test'))
61 | })
62 |
63 | test('strTest', (t) => {
64 | t.plan(5)
65 | let strTest = tyval.string().min(5).max(10).alphanum()
66 | t.is(typeof strTest, 'function')
67 | t.true(strTest('abc123'))
68 | t.false(strTest('abc'))
69 | t.false(strTest('123'))
70 | t.false(strTest(123))
71 | })
72 |
73 | test('string.mail', (t) => {
74 | t.plan(9)
75 | t.is(typeof tyval.string.mail, 'function')
76 | let mail = tyval.string().mail()
77 | t.is(typeof mail, 'function')
78 | t.true(mail('test@gmail.com'))
79 | t.true(mail('make.test@sub.domain.com'))
80 | t.true(mail('the.answer.is.42@sub.sub.domain.eu'))
81 | t.false(mail('test@gmail.'))
82 | t.false(mail('test.gmail@.it'))
83 | t.false(mail('t.e.s.t.@g.e'))
84 | t.false(mail('t@t.t'))
85 | })
86 |
87 | test('string.ipv4', (t) => {
88 | t.plan(9)
89 | t.is(typeof tyval.string.ipv4, 'function')
90 | let ip = tyval.string().ipv4()
91 | t.is(typeof ip, 'function')
92 | t.true(ip('192.168.20.20'))
93 | t.true(ip('0.255.0.255'))
94 | t.true(ip('0.0.0.0'))
95 | t.false(ip('192.168'))
96 | t.false(ip('192.168.20.256'))
97 | t.false(ip('::1'))
98 | t.false(ip('2001:0db8::1428:57ab'))
99 | })
100 |
101 | test('string.ipv6', (t) => {
102 | t.plan(13)
103 | t.is(typeof tyval.string.ipv6, 'function')
104 | let ip = tyval.string().ipv6()
105 | t.is(typeof ip, 'function')
106 | t.true(ip('2001:0db8:0000:0000:0000:0000:1428:57ab'))
107 | t.true(ip('2001:0db8:0000:0000::1428:57ab'))
108 | t.true(ip('2001:0db8:0:0:0:0:1428:57ab'))
109 | t.true(ip('2001:0db8:0::0:1428:57ab'))
110 | t.true(ip('2001:0db8::1428:57ab'))
111 | t.false(ip('2001:0db8::25de::cade'))
112 | t.false(ip('1111:2222:3333:4444::5555:'))
113 | t.false(ip('2001:db8:85a3::8a2e:37023:7334'))
114 | t.false(ip('::ffff:257.1.2.3'))
115 | t.false(ip('1.2.3.4::'))
116 | t.false(ip('2001:db8:85a3::8a2e:370k:7334'))
117 | })
118 |
119 | test('string.base64', (t) => {
120 | t.plan(6)
121 | t.is(typeof tyval.string.base64, 'function')
122 | let b64 = tyval.string().base64()
123 | t.is(typeof b64, 'function')
124 | t.true(b64('SSdtIGEgYmFzZTY0IHN0cmluZw=='))
125 | t.true(b64('MSsxPTU1'))
126 | t.false(b64('I\'m not a base64 string'))
127 | t.false(b64('Hello1World=='))
128 | })
129 |
130 | test('string.JSON', (t) => {
131 | t.plan(4)
132 | t.is(typeof tyval.string.JSON, 'function')
133 | let isJSON = tyval.string().JSON()
134 | t.is(typeof isJSON, 'function')
135 | t.true(isJSON('{"valid":true}'))
136 | t.false(isJSON('{"valid:false}'))
137 | })
138 |
139 | test('string.uuid', (t) => {
140 | t.plan(6)
141 | t.is(typeof tyval.string.uuid, 'function')
142 | let uuid = tyval.string().uuid()
143 | t.is(typeof uuid, 'function')
144 | t.true(uuid('6fa459ea-ee8a-3ca4-894e-db77e160355e'))
145 | t.true(uuid('16fd2706-8baf-433b-82eb-8c7fada847da'))
146 | t.true(uuid('886313e1-3b8a-5372-9b90-0c9aee199e5d'))
147 | t.false(uuid('what?'))
148 | })
149 |
150 | test('string.MAC', (t) => {
151 | t.plan(4)
152 | t.is(typeof tyval.string.MAC, 'function')
153 | let isMac = tyval.string().MAC()
154 | t.is(typeof isMac, 'function')
155 | t.true(isMac('48-2C-6A-1E-59-3D'))
156 | t.false(isMac('nope!'))
157 | })
158 |
159 | test('string.md5', (t) => {
160 | t.plan(4)
161 | t.is(typeof tyval.string.md5, 'function')
162 | let isMd5 = tyval.string().md5()
163 | t.is(typeof isMd5, 'function')
164 | t.true(isMd5('b4dd7f0b0ca6c25dd46cc096e45158eb'))
165 | t.false(isMd5('maybe but not'))
166 | })
167 |
168 | /* eslint-disable no-undef */
169 | test('string.extend', (t) => {
170 | t.plan(4)
171 | tyval.string.extend(function empty () {
172 | if (value.length > 0) {
173 | return false
174 | }
175 | })
176 | t.is(typeof tyval.string.empty, 'function')
177 | let empty = tyval.string().empty()
178 | t.is(typeof empty, 'function')
179 | t.true(empty(''))
180 | t.false(empty('.'))
181 | })
182 | /* eslint-disable no-undef */
183 |
184 | test('string.card', (t) => {
185 | t.plan(15)
186 | t.is(typeof tyval.string.card, 'function')
187 | let card = tyval.string().card('jcb')
188 | t.true(card('3530111333300000'))
189 | t.false(card('378282246310005'))
190 |
191 | card = tyval.string().card('visa')
192 | t.true(card('4012888888881881'))
193 | t.false(card('3566002020360505'))
194 |
195 | card = tyval.string().card('discover')
196 | t.true(card('6011000990139424'))
197 | t.false(card('4111111111111111'))
198 |
199 | card = tyval.string().card('dinersclub')
200 | t.true(card('38520000023237'))
201 | t.false(card('6011111111111117'))
202 |
203 | card = tyval.string().card('mastercard')
204 | t.true(card('5105105105105100'))
205 | t.false(card('38520000023237'))
206 |
207 | card = tyval.string().card('americanexpress')
208 | t.true(card('371449635398431'))
209 | t.false(card('5555555555554444'))
210 |
211 | try {
212 | card = tyval.string().card('lannister')
213 | t.fail()
214 | } catch (e) {
215 | t.is(e.message, 'lannister card is not supported')
216 | t.pass()
217 | }
218 | })
219 |
--------------------------------------------------------------------------------
/test/test-runner.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env zsh
2 |
3 | # This script run test and bench under Node v4, v5 and v6.
4 | # By default it runs only the test, if you pass '--bench' it will run the benchmark as well.
5 |
6 | set -e
7 |
8 | . ~/.nvm/nvm.sh
9 |
10 | bench=${1:-default}
11 |
12 | echo "\n-------------------------"
13 | echo "| Test under Node.js v4 |"
14 | echo "-------------------------"
15 | nvm use "4.5.0"
16 | npm test
17 | if [ $bench == "--bench" ]
18 | then
19 | npm run bench
20 | fi
21 |
22 | echo "\n-------------------------"
23 | echo "| Test under Node.js v5 |"
24 | echo "-------------------------"
25 | nvm use "5.11.1"
26 | npm test
27 | if [ $bench == "--bench" ]
28 | then
29 | npm run bench
30 | fi
31 |
32 | echo "\n-------------------------"
33 | echo "| Test under Node.js v6 |"
34 | echo "-------------------------"
35 | nvm use "6.5.0"
36 | npm test
37 | if [ $bench == "--bench" ]
38 | then
39 | npm run bench
40 | fi
41 |
42 | echo "\n--------------------"
43 | echo "| All test passed! |"
44 | echo "--------------------"
45 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const tap = require('tap')
4 | const test = tap.test
5 | const tyval = require('../tyval')
6 |
7 | test('tyval', (t) => {
8 | t.plan(1)
9 | t.is(typeof tyval, 'object')
10 | })
11 |
12 | /* eslint-disable no-undef, no-unused-vars */
13 | test('common.toFunction', (t) => {
14 | const common = require('../lib/common')
15 | t.plan(2)
16 | t.is(typeof common.toFunction, 'function')
17 | t.is(typeof common.toFunction(() => {}), 'function')
18 | })
19 |
20 | test('common.toFunction - well formatted', (t) => {
21 | const common = require('../lib/common')
22 | t.plan(3)
23 | const num = function () {
24 | return toFunction(null, function () {
25 | if (typeof value !== 'number') {
26 | return false
27 | }
28 | })
29 | }
30 | const toFunction = common.toFunction(num)
31 | t.is(typeof num(), 'function')
32 | t.true(num()(5))
33 | t.false(num()('5'))
34 | })
35 |
36 | test('common.toFunction - bad formatted', (t) => {
37 | const common = require('../lib/common')
38 | t.plan(3)
39 | const num = function () {
40 | return toFunction(null, function () {if(typeof value !=='number' ){return false } }) // eslint-disable-line
41 | }
42 | const toFunction = common.toFunction(num)
43 | t.is(typeof num(), 'function')
44 | t.true(num()(5))
45 | t.false(num()('5'))
46 | })
47 |
48 | test('common.toFunction - arrow function', (t) => {
49 | const common = require('../lib/common')
50 | t.plan(3)
51 | const num = function () {
52 | return toFunction(null, () => {
53 | if (typeof value !== 'number') {
54 | return false
55 | }
56 | })
57 | }
58 | const toFunction = common.toFunction(num)
59 | t.is(typeof num(), 'function')
60 | t.true(num()(5))
61 | t.false(num()('5'))
62 | })
63 |
64 | test('common.toFunction - parameters', (t) => {
65 | const common = require('../lib/common')
66 | t.plan(3)
67 | const num = function (max) {
68 | return toFunction(null, function () {
69 | if (value !== $max$) {
70 | return false
71 | }
72 | }, { $max$: max })
73 | }
74 | const toFunction = common.toFunction(num)
75 | t.is(typeof num(), 'function')
76 | t.true(num(5)(5))
77 | t.false(num(5)('5'))
78 | })
79 |
80 | test('common.toFunction - throw', (t) => {
81 | const common = require('../lib/common')
82 | t.plan(4)
83 | try {
84 | common.toFunction(null)
85 | t.fail()
86 | } catch (e) {
87 | t.pass()
88 | }
89 |
90 | const toFunction = common.toFunction(() => {})
91 | try {
92 | toFunction(5)
93 | t.fail()
94 | } catch (e) {
95 | t.pass()
96 | }
97 | try {
98 | toFunction(null, 5)
99 | t.fail()
100 | } catch (e) {
101 | t.pass()
102 | }
103 | try {
104 | toFunction(null, () => {}, 5)
105 | t.fail()
106 | } catch (e) {
107 | t.pass()
108 | }
109 | })
110 |
111 | test('or internal function declaration', (t) => {
112 | t.plan(6)
113 | t.is(typeof tyval.or, 'function')
114 | let validation = tyval.or(tyval.number().min(1).max(10), tyval.string().min(1).max(10))
115 | t.is(typeof validation, 'function')
116 | t.true(validation(5))
117 | t.true(validation('test'))
118 | t.false(validation(50))
119 | t.false(validation('I will fail'))
120 | })
121 |
122 | test('or external function declaration', (t) => {
123 | t.plan(6)
124 | t.is(typeof tyval.or, 'function')
125 | const num = tyval.number().min(1).max(10)
126 | const str = tyval.string().min(1).max(10)
127 | let validation = tyval.or(num, str)
128 | t.is(typeof validation, 'function')
129 | t.true(validation(5))
130 | t.true(validation('test'))
131 | t.false(validation(50))
132 | t.false(validation('I will fail'))
133 | })
134 |
135 | test('or mixed function declaration', (t) => {
136 | t.plan(6)
137 | t.is(typeof tyval.or, 'function')
138 | const num = tyval.number().min(1).max(10)
139 | let validation = tyval.or(num, tyval.string().min(1).max(10))
140 | t.is(typeof validation, 'function')
141 | t.true(validation(5))
142 | t.true(validation('test'))
143 | t.false(validation(50))
144 | t.false(validation('I will fail'))
145 | })
146 |
147 | test('or multiple', (t) => {
148 | t.plan(8)
149 | t.is(typeof tyval.or, 'function')
150 | const num = tyval.number().min(1).max(10)
151 | const str = tyval.string().min(1).max(10)
152 | const obj = tyval.object().empty()
153 | let validation = tyval.or(num, str, obj)
154 | t.is(typeof validation, 'function')
155 | t.true(validation(5))
156 | t.true(validation('test'))
157 | t.true(validation({}))
158 | t.false(validation(50))
159 | t.false(validation('I will fail'))
160 | t.false(validation({ a: '1' }))
161 | })
162 |
163 | test('or number range', (t) => {
164 | t.plan(3)
165 | const num1 = tyval.number().max(1)
166 | const num2 = tyval.number().min(10)
167 | // represents n < 1 || n > 10
168 | const or = tyval.or(num1, num2)
169 | t.true(or(20))
170 | t.true(or(-3))
171 | t.false(or(5))
172 | })
173 |
--------------------------------------------------------------------------------
/tyval.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Project: Tyval
3 | * Version: 4.0.0
4 | * Author: delvedor
5 | * Twitter: @delvedor
6 | * License: MIT
7 | * GitHub: https://github.com/delvedor/Tyval
8 | */
9 |
10 | 'use strict'
11 |
12 | module.exports = {
13 | number: require('./lib/number'),
14 | string: require('./lib/string'),
15 | array: require('./lib/array'),
16 | date: require('./lib/date'),
17 | boolean: require('./lib/boolean'),
18 | object: require('./lib/object'),
19 | error: require('./lib/error'),
20 | or: require('./lib/common').or
21 | }
22 |
--------------------------------------------------------------------------------
/tyval.min.js:
--------------------------------------------------------------------------------
1 | !function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o$max$)return!1},{$max$:max})},array.min=function(min){if("number"!=typeof min)throw new TypeError("array.min - min is not a number");return toFunction(this,function(){if(value.length<$min$)return!1},{$min$:min})},Object.defineProperty(array,"length",{writable:!0}),array.length=function(len){if("number"!=typeof len)throw new TypeError("array.length - len is not a number");return toFunction(this,function(){if(value.length!==$length$)return!1},{$length$:len})},array.contains=function(containValue){return toFunction(this,function(){if(value.indexOf($containValue$)===-1)return!1},{$containValue$:containValue})},array.items=function(func){if("function"!=typeof func)throw new TypeError("array.items parameter must be a function");return toFunction(this,function(){for(var validate=$func$,i=0,len=value.length;i=$newDate$)return!1},{$newDate$:d.getTime()})},date.higher=function(d){return toFunction(this,function(){if(value.getTime()<=$newDate$)return!1},{$newDate$:d.getTime()})},date.extend=function(func){return extend(this,func,toFunction)};var toFunction=buildToFunction(date);module.exports=date},{"./common":3}],5:[function(require,module,exports){"use strict";var buildToFunction=require("./common").toFunction,extend=require("./common").extend,error=function(){return toFunction(null,function(){if(!(value instanceof Error))return!1})};error.RangeError=function(){return toFunction(this,function(){if(!(value instanceof RangeError))return!1})},error.ReferenceError=function(){return toFunction(this,function(){if(!(value instanceof ReferenceError))return!1})},error.SyntaxError=function(){return toFunction(this,function(){if(!(value instanceof SyntaxError))return!1})},error.TypeError=function(){return toFunction(this,function(){if(!(value instanceof TypeError))return!1})},error.message=function(message){if("string"!=typeof message)throw new Error("error message must be a string");return toFunction(this,function(){if(value.message!==$message$)return!1},{$message$:message})},error.extend=function(func){return extend(this,func,toFunction)};var toFunction=buildToFunction(error);module.exports=error},{"./common":3}],6:[function(require,module,exports){"use strict";var buildToFunction=require("./common").toFunction,extend=require("./common").extend,number=function(){return toFunction(null,function(){if("number"!=typeof value)return!1})};number.max=function(max){if("number"!=typeof max)throw new TypeError("number.max - max is not a number");return toFunction(this,function(){if(value>$max$)return!1},{$max$:max})},number.min=function(min){if("number"!=typeof min)throw new TypeError("number.min - min is not a number");return toFunction(this,function(){if(value<$min$)return!1},{$min$:min})},number.positive=function(){return toFunction(this,function(){if(value<0)return!1})},number.negative=function(){return toFunction(this,function(){if(value>0)return!1})},number.integer=function(){return toFunction(this,function(){if(!(Math.floor(value)===value||value>9007199254740992||value<-9007199254740992))return!1})},number.float=function(){return toFunction(this,function(){if(Math.floor(value)===value||value>9007199254740992||value<-9007199254740992)return!1})},number.safeInteger=function(){return toFunction(this,function(){if(value>9007199254740991||value<-9007199254740991)return!1})},number.finite=function(){return toFunction(this,function(){if(!Number.isFinite(value))return!1})},number.multiple=function(mult){if("number"!=typeof mult)throw new TypeError("number.multiple - mult is not a number");return toFunction(this,function(){if(value%$multiple$!==0)return!1},{$multiple$:mult})},number.notNaN=function(){return toFunction(this,function(){if(Number.isNaN(value))return!1})},number.port=function(options){return options=options||{},toFunction(this,function(){if(value>65535||value<($reserved$?1024:0))return!1},{$reserved$:options.reserved||!1})},number.extend=function(func){return extend(this,func,toFunction)};var toFunction=buildToFunction(number);module.exports=number},{"./common":3}],7:[function(require,module,exports){"use strict";var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(obj){return typeof obj}:function(obj){return obj&&"function"==typeof Symbol&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj},buildToFunction=require("./common").toFunction,extend=require("./common").extend,object=function(){return toFunction(null,function(){if("object"!==("undefined"==typeof value?"undefined":_typeof(value)))return!1})};object.empty=function(){return toFunction(this,function(){if(Object.keys(value).length>0)return!1})},object.notNull=function(){return toFunction(this,function(){if(null===value)return!1})},object.notArray=function(){return toFunction(this,function(){if(Array.isArray(value))return!1})},object.notDate=function(){return toFunction(this,function(){if(value instanceof Date)return!1})},object.notRegExp=function(){return toFunction(this,function(){if(value instanceof RegExp)return!1})},object.has=function(haskey,options){if("string"!=typeof haskey)throw new TypeError("object.has - haskey is not a string");return options=options||{},options.fast?toFunction(this,function(){if(void 0===value[$haskey$])return!1},{$haskey$:haskey}):toFunction(this,function(){if(!value.hasOwnProperty($haskey$))return!1},{$haskey$:haskey})},object.hasNot=function(hasnotkey,options){if("string"!=typeof hasnotkey)throw new TypeError("object.hasNot - hasnotkey is not a string");return options=options||{},options.fast?toFunction(this,function(){if(void 0!==value[$hasnotkey$])return!1},{$hasnotkey$:hasnotkey}):toFunction(this,function(){if(value.hasOwnProperty($hasnotkey$))return!1},{$hasnotkey$:hasnotkey})},object.extend=function(func){return extend(this,func,toFunction)};var toFunction=buildToFunction(object);module.exports=object},{"./common":3}],8:[function(require,module,exports){"use strict";"use string";var buildToFunction=require("./common").toFunction,extend=require("./common").extend,string=function(){return toFunction(null,function(){if("string"!=typeof value)return!1})};string.alphanum=function(){return toFunction(this,function(){var reg=/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+[0-9a-z]+$/i;if(!reg.test(value))return!1})},string.regex=function(reg){if(!(reg instanceof RegExp))throw new TypeError("string.regex - reg is not a RegExp");return toFunction(this,function(){var reg=$reg$;if(!reg.test(value))return!1},{$reg$:reg})},string.max=function(max){if("number"!=typeof max)throw new TypeError("string.max - max is not a number");return toFunction(this,function(){if(value.length>$max$)return!1},{$max$:max})},string.min=function(min){if("number"!=typeof min)throw new TypeError("string.min - min is not a number");return toFunction(this,function(){if(value.length<$min$)return!1},{$min$:min})},Object.defineProperty(string,"length",{writable:!0}),string.length=function(len){if("number"!=typeof len)throw new TypeError("string.length - len is not a number");return toFunction(this,function(){if(value.length!==$length$)return!1},{$length$:len})},string.mail=function(){return toFunction(this,function(){var mailReg=/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;if(!mailReg.test(value))return!1})},string.ipv4=function(){return toFunction(this,function(){var ipReg=/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;if(!ipReg.test(value))return!1})},string.ipv6=function(){return toFunction(this,function(){var ipReg=/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;if(!ipReg.test(value))return!1})},string.base64=function(){return toFunction(this,function(){var base64Reg=/^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{4}|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)$/;if(!base64Reg.test(value))return!1})},string.JSON=function(){return toFunction(this,function(){try{JSON.parse(value)}catch(e){return!1}})},string.uuid=function(){return toFunction(this,function(){var uuidReg=/[a-f0-9]{8}-?[a-f0-9]{4}-?[1-5][a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}/i;if(!uuidReg.test(value))return!1})},string.MAC=function(){return toFunction(this,function(){var macReg=/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;if(!macReg.test(value))return!1})},string.md5=function(){return toFunction(this,function(){var md5Reg=/^[a-f0-9]{32}$/;if(!md5Reg.test(value))return!1})},string.card=function(cardType){if("string"!=typeof cardType)throw new Error("cardType must be a string");var cards={jcb:/^(?:2131|1800|35\d{3})\d{11}$/,visa:/^4\d{12}(?:\d{3})?$/,discover:/^6(?:011|5\d{2})\d{12}$/,dinersclub:/^3(?:0[0-5]|[68]\d)\d{11}$/,mastercard:/^5[1-5]\d{14}$/,americanexpress:/^3[47]\d{13}$/};if(!cards[cardType])throw new Error(cardType+" card is not supported");return toFunction(this,function(){if(!$reg$.test(value))return!1},{$reg$:cards[cardType]})},string.extend=function(func){return extend(this,func,toFunction)};var toFunction=buildToFunction(string);module.exports=string},{"./common":3}],9:[function(require,module,exports){"use strict";window.tyval={number:require("./lib/number"),string:require("./lib/string"),array:require("./lib/array"),date:require("./lib/date"),boolean:require("./lib/boolean"),object:require("./lib/object"),error:require("./lib/error"),or:require("./lib/common").or}},{"./lib/array":1,"./lib/boolean":2,"./lib/common":3,"./lib/date":4,"./lib/error":5,"./lib/number":6,"./lib/object":7,"./lib/string":8}]},{},[9]);
--------------------------------------------------------------------------------