-
-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
1,789 additions
and
1,674 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Enforce templates | ||
|
||
When you have common patterns you need to repeat in multiple places, it might be simpler to store them as templates. | ||
|
||
For example, let's assume that all across our systems, a username must be a non-numeric string that's longer than 3 characters. | ||
|
||
```js | ||
enforce(username).isString().isNotEmpty().isNotNumeric().longerThan(3); | ||
``` | ||
|
||
This is quite simple to understand, but if you have to keep it up-to-date in every place you validate a username, you may eventually have inconsistent or out-of-date validations. | ||
|
||
It can be beneficial in that case to keep this enforcement as a template for later use: | ||
|
||
```js | ||
const Username = enforce.template( | ||
enforce.isString().isNotEmpty().isNotNumeric().longerThan(3) | ||
); | ||
``` | ||
|
||
And then, anywhere else you can use your new `Username` template to validate usernames all across your application: | ||
|
||
```js | ||
Username('myUsername'); // passes | ||
Username('1234'); // throws | ||
Username('ab'); // throws | ||
``` | ||
|
||
You can also use templates inside other compound rules, such as `shape`, `isArrayOf` or `anyOf`. | ||
|
||
```js | ||
enforce({ | ||
username: 'someusername', | ||
}).shape({ username: Username }); | ||
|
||
enforce(['user1', 'user2']).isArrayOf(Username); | ||
``` | ||
|
||
Templates can also be nested and composited: | ||
|
||
```js | ||
const RequiredField = enforce.template(enforce.isNotEmpty()); | ||
const NumericString = enforce.template(enforce.isNumeric().isString()); | ||
|
||
const EvenNumeric = enforce.template( | ||
RequiredField, | ||
NumericString, | ||
enforce.isEven() | ||
); | ||
|
||
EvenNumeric('10'); // pases | ||
EvenNumeric('1'); // throws | ||
``` |
91 changes: 91 additions & 0 deletions
91
packages/n4s/src/enforce/__tests__/enforce.template.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import enforce from 'enforce'; | ||
import runtimeRules from 'runtimeRules'; | ||
|
||
describe('enforce.template', () => { | ||
test('enforce has `template` static function', () => { | ||
expect(typeof enforce.template).toBe('function'); | ||
}); | ||
|
||
describe('Return value', () => { | ||
it('Should return a function', () => { | ||
const x = enforce.template(enforce.isArray(), enforce.longerThan(5)); | ||
|
||
expect(typeof x).toBe('function'); | ||
}); | ||
|
||
it('Should have a static function called `test`', () => { | ||
const x = enforce.template(enforce.isArray(), enforce.longerThan(5)); | ||
|
||
expect(typeof x.test).toBe('function'); | ||
}); | ||
}); | ||
|
||
describe('When the returned function gets called', () => { | ||
it('Should throw an error when invalid', () => { | ||
const x = enforce.template(enforce.isArray(), enforce.longerThan(2)); | ||
const y = enforce.template(enforce.isString(), enforce.isNumeric()); | ||
expect(() => x([])).toThrow(); | ||
expect(() => y('')).toThrow(); | ||
expect(() => x([1])).toThrow(); | ||
expect(() => x('hello')).toThrow(); | ||
expect(() => y('hello')).toThrow(); | ||
}); | ||
|
||
it('Should return silently when valid', () => { | ||
const x = enforce.template(enforce.isArray(), enforce.longerThan(2)); | ||
const y = enforce.template(enforce.isString(), enforce.isNumeric()); | ||
|
||
x([1, 2, 3]); | ||
y('123'); | ||
}); | ||
|
||
it('Should return rules proxy', () => { | ||
const x = enforce.template(enforce.isArray()); | ||
expect(x([])).toEqual(enforce(1)); | ||
Object.keys(runtimeRules).forEach(k => { | ||
expect(typeof x([])[k]).toBe('function'); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('When the `test` function gets called', () => { | ||
it('Should return `false` when invalid', () => { | ||
const x = enforce.template(enforce.isNumber().greaterThan(50)); | ||
const y = enforce.template( | ||
enforce.isString().isNumeric(), | ||
enforce.isOdd() | ||
); | ||
|
||
expect(x.test(10)).toBe(false); | ||
expect(x.test('90')).toBe(false); | ||
expect(y.test(true)).toBe(false); | ||
expect(x.test('90')).toBe(false); | ||
}); | ||
it('Should return `true` when valid', () => { | ||
const x = enforce.template(enforce.isNumber().greaterThan(50)); | ||
const y = enforce.template( | ||
enforce.isString().isNumeric(), | ||
enforce.isOdd() | ||
); | ||
|
||
expect(x.test(51)).toBe(true); | ||
expect(y.test('11')).toBe(true); | ||
}); | ||
}); | ||
|
||
describe('Nested templates', () => { | ||
it('Should validate all joined templates', () => { | ||
const X = enforce.template(enforce.isString(), enforce.longerThan(2)); | ||
const Y = enforce.template(enforce.isNumeric()); | ||
const Z = enforce.template(enforce.isEven()); | ||
|
||
expect(() => enforce.template(X, Y, Z)('a')).toThrow(); | ||
expect(() => enforce.template(X, Y, Z)('abc')).toThrow(); | ||
expect(() => enforce.template(X, Y, Z)('111')).toThrow(); | ||
expect(() => enforce.template(X, Y, Z)(112)).toThrow(); | ||
enforce.template(X, Y, Z)('112'); | ||
enforce.template(X, Y)('111'); | ||
enforce.template(X)('abc'); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import bindLazyRule from 'bindLazyRule'; | ||
import genRuleProxy from 'genRuleProxy'; | ||
import proxySupported from 'proxySupported'; | ||
import runtimeRules from 'runtimeRules'; | ||
|
||
export default function bindExtend(enforce, Enforce) { | ||
enforce.extend = customRules => { | ||
Object.assign(runtimeRules, customRules); | ||
|
||
if (!proxySupported()) { | ||
genRuleProxy(Enforce, bindLazyRule); | ||
} | ||
|
||
return enforce; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import runner from 'enforceRunner'; | ||
import genRuleProxy from 'genRuleProxy'; | ||
import isFunction from 'isFunction'; | ||
import runLazyRules from 'runLazyRules'; | ||
import runtimeRules from 'runtimeRules'; | ||
|
||
export default function bindTemplate(enforce) { | ||
enforce.template = (...rule) => { | ||
const template = value => { | ||
runner(runLazyRules.bind(null, rule), value); | ||
const proxy = genRuleProxy({}, ruleName => (...args) => { | ||
runner(runtimeRules[ruleName], value, args); | ||
return proxy; | ||
}); | ||
return proxy; | ||
}; | ||
|
||
template.test = getValue => | ||
runLazyRules(rule, isFunction(getValue) ? getValue() : getValue); | ||
|
||
return template; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
- [Getting Started](./getting_started) | ||
- [enforce](./enforce){{ENFORCE_DOCS}} | ||
- [The result object](./result) | ||
- [test](./test) | ||
- [How to fail a test](./test#failing_a_test) | ||
- [Warn only tests](./warn) | ||
- [Grouping tests](./group) | ||
- [Understanding Vest's state](./state) | ||
- Advanced cases | ||
- [Cross Field Validations](./cross_field_validations) | ||
- [Excluding or including tests](./exclusion) | ||
- [Using with node](./node) | ||
- [Utilities](./utilities) |
Oops, something went wrong.