vest 3.2.4-dev-c9788a → 3.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +115 -0
  2. package/any.d.ts +3 -0
  3. package/any.js +1 -0
  4. package/classNames.d.ts +14 -0
  5. package/classNames.js +1 -0
  6. package/docs/.nojekyll +0 -0
  7. package/docs/README.md +115 -0
  8. package/docs/_assets/favicon.ico +0 -0
  9. package/docs/_assets/vest-logo.png +0 -0
  10. package/docs/_sidebar.md +19 -0
  11. package/docs/_sidebar.md.bak +14 -0
  12. package/docs/cross_field_validations.md +79 -0
  13. package/docs/enforce.md +18 -0
  14. package/docs/enforce.md.bak +13 -0
  15. package/docs/exclusion.md +128 -0
  16. package/docs/getting_started.md +79 -0
  17. package/docs/group.md +142 -0
  18. package/docs/index.html +41 -0
  19. package/docs/migration.md +107 -0
  20. package/docs/n4s/compound.md +187 -0
  21. package/docs/n4s/custom.md +52 -0
  22. package/docs/n4s/external.md +54 -0
  23. package/docs/n4s/rules.md +1282 -0
  24. package/docs/n4s/template.md +53 -0
  25. package/docs/node.md +43 -0
  26. package/docs/optional.md +51 -0
  27. package/docs/result.md +238 -0
  28. package/docs/state.md +102 -0
  29. package/docs/test.md +172 -0
  30. package/docs/utilities.md +105 -0
  31. package/docs/warn.md +82 -0
  32. package/enforce.d.ts +230 -0
  33. package/esm/package.json +1 -0
  34. package/esm/vest.es.development.js +2493 -0
  35. package/esm/vest.es.production.js +2490 -0
  36. package/esm/vest.es.production.min.js +1 -0
  37. package/package.json +65 -12
  38. package/promisify.d.ts +7 -0
  39. package/{dist/umd/promisify.production.js → promisify.js} +1 -1
  40. package/schema.d.ts +26 -0
  41. package/schema.js +1 -0
  42. package/vest.cjs.development.js +2494 -0
  43. package/vest.cjs.production.js +2491 -0
  44. package/vest.cjs.production.min.js +1 -0
  45. package/vest.d.ts +249 -0
  46. package/vest.js +7 -0
  47. package/vest.umd.development.js +2711 -0
  48. package/vest.umd.production.js +2708 -0
  49. package/vest.umd.production.min.js +1 -0
  50. package/vestResult.d.ts +105 -0
  51. package/CHANGELOG.md +0 -52
  52. package/LICENSE +0 -21
  53. package/dist/cjs/classnames.development.js +0 -67
  54. package/dist/cjs/classnames.production.js +0 -1
  55. package/dist/cjs/promisify.development.js +0 -20
  56. package/dist/cjs/promisify.production.js +0 -1
  57. package/dist/cjs/vest.development.js +0 -1616
  58. package/dist/cjs/vest.production.js +0 -1
  59. package/dist/es/classnames.development.js +0 -65
  60. package/dist/es/classnames.production.js +0 -1
  61. package/dist/es/promisify.development.js +0 -18
  62. package/dist/es/promisify.production.js +0 -1
  63. package/dist/es/vest.development.js +0 -1604
  64. package/dist/es/vest.production.js +0 -1
  65. package/dist/umd/classnames.development.js +0 -73
  66. package/dist/umd/classnames.production.js +0 -1
  67. package/dist/umd/promisify.development.js +0 -26
  68. package/dist/umd/vest.development.js +0 -1622
  69. package/dist/umd/vest.production.js +0 -1
  70. package/index.js +0 -7
@@ -0,0 +1,105 @@
1
+ # Utilities and helpers
2
+
3
+ ## `classNames` for simplifying UI code
4
+
5
+ After validating user input, you usually need to also indicate the validation result on the page - most of the times by adding a class to your input element. One of the difficulties you are likely to face is that the logic for setting the class is not always the negation of `hasErrors`.
6
+
7
+ ```js
8
+ const addIsValidClass = !res.hasErrors('fieldName'); // this does not ALWAYS mean 'valid'
9
+ ```
10
+
11
+ What about when the field is skipped or not validated yet? It does not have errors, so `res.hasErrors('fieldName')` will return `false`, and by that logic, you might mistakenly add a `is-valid` class to your element.
12
+
13
+ In this case you will also need to check if the test actually ran - so:
14
+
15
+ ```js
16
+ const addIsValidClass = res.tests[fieldName] && !res.hasErrors('fieldName');
17
+ ```
18
+
19
+ But this can get pretty cumbersome when added to multiple fields with different criteria (untested, invalid, hasWarning...).
20
+
21
+ This is what `vest/classNames` is for. It is a tiny utility function, that allows you to specify classnames to be added for each criteria.
22
+
23
+ The way it works is simple. You call `classNames` with your result object, and the list of classes you want to be added for whenever the field is tested, untested, has warning or is invalid. It then returns a function that when called with a field name, returns a space delimited string of classes. If more than one class applies (both tested and invalid, for example) they will both be added to the string.
24
+
25
+ ```js
26
+ import classNames from 'vest/classNames';
27
+ import suite from './suite';
28
+
29
+ const res = suite(data);
30
+
31
+ const cn = classNames(res, {
32
+ untested: 'is-untested', // will only be applied if the provided field did not run yet
33
+ tested: 'some-tested-class', // will only be applied if the provided field did run
34
+ invalid: 'my_invalid_class', // will only be applied if the provided field ran at least once and has an error
35
+ valid: 'my_valid_class', // will only be applied if the provided field ran at least once does not have errors or warnings
36
+ warning: 'my_warning_class', // will only be applied if the provided field ran at least once and has a warning
37
+ });
38
+
39
+ const fieldOneClasses = cn('field_1'); // "is-untested"
40
+ const fieldTwoClasses = cn('field_2'); // "some-tested-class my_invalid_class"
41
+ const fieldThreeClasses = cn('field_3'); // "some-tested-class my_warning_class"
42
+ ```
43
+
44
+ ## `any()` for OR relationship tests
45
+
46
+ Sometimes you need to have `OR` (`||`) relationship in your validations, this is tricky to do on your own, and `any()` simplifies this process.
47
+
48
+ The general rule for using `any()` in your validation is when you can say: "At least one of the following has to pass".
49
+
50
+ A good example would be: When your validated field can be either empty (not required), but when field - has to pass some validation.
51
+
52
+ ### Usage
53
+
54
+ `any()` accepts an infinite number of arguments, all of which are functions. It returns a boolean, that can be used as the return value of a test function.
55
+
56
+ The only difference is - if any of the supplied tests passes, the success condition is met and `any()` returns true.
57
+
58
+ ```js
59
+ import { create, test, enforce } from 'vest';
60
+ import any from 'vest/any';
61
+
62
+ create('Checkout', () => {
63
+ test('coupon', 'When filled, must be at least 5 chars', () =>
64
+ any(
65
+ () => enforce(data.coupon).isEmpty(),
66
+ () => enforce(data.coupon).longerThanOrEquals(5)
67
+ )
68
+ );
69
+ });
70
+ ```
71
+
72
+ ## `promisify()`
73
+
74
+ Promisify is a function that enables you to run your async validations as a [Javascript Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
75
+ This can be useful when running async validations on the server, or when you do not need the partial validation results.
76
+
77
+ !> **NOTE** The Promise is resolved when all tests finish running.
78
+
79
+ ### Usage
80
+
81
+ `promisify()` accepts a validation suite declaration, and returns a function that when called, returns a Promise.
82
+
83
+ ```js
84
+ import { create, test, skipWhen } from 'vest';
85
+ import promisify from 'vest/promisify';
86
+
87
+ const suite = promisify(
88
+ create('CreateNewUser', data => {
89
+ test('email', 'The email already exists', () => doesEmailExist(data.email));
90
+ test('username', 'The username already exists', () =>
91
+ doesUsernameExist(data.username)
92
+ );
93
+ })
94
+ );
95
+
96
+ suite(data).then(res => {
97
+ skipWhen(res.hasErrors('email'), () => {
98
+ /* ... */
99
+ });
100
+
101
+ skipWhen(res.hasErrors('username'), () => {
102
+ /* ... */
103
+ });
104
+ });
105
+ ```
package/docs/warn.md ADDED
@@ -0,0 +1,82 @@
1
+ # Warn only tests
2
+
3
+ By default, a failing test has a severity of `error`. Sometimes you may need to lower the severity level of a given test to `warn` so that even when it fails, it should not prevent submission. An example of this would be validating password strength.
4
+
5
+ To set a test's severity level to `warn`, you need to simply call Vest's warn function from your test body.
6
+
7
+ ```js
8
+ import { create, test, enforce, warn } from 'vest';
9
+
10
+ const suite = create('Password', data => {
11
+ test('password', 'A password must have at least 6 characters', () => {
12
+ enforce(data.password).longerThan(5);
13
+ }); // this test has a severity level of `error`
14
+
15
+ test('password', 'Your password strength is: WEAK', () => {
16
+ warn();
17
+
18
+ enforce(data.password).matches(
19
+ /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]$/
20
+ );
21
+ }); // this test has a severity level of `warn`
22
+
23
+ test('password', 'Your password strength is: MEDIUM', () => {
24
+ warn();
25
+
26
+ enforce(data.password).matches(
27
+ /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]$/
28
+ );
29
+ }); // this test has a severity level of `warn`
30
+ });
31
+
32
+ const validationResult = suite(data);
33
+ ```
34
+
35
+ **Limitations when using warn()**
36
+
37
+ - You may only use warn from within the body of a `test` function.
38
+ - When using `warn()` in an async test you should call the `warn` function in the sync portion of your test (and not after an `await` call or in the Promise body). Ideally, you want to call `warn()` at the top of your test function.
39
+
40
+ ```js
41
+ // ✔
42
+ test('password', async () => {
43
+ warn();
44
+ return await someAsyncFunction();
45
+ });
46
+
47
+ // ✔
48
+ test('password', () => {
49
+ warn();
50
+ return anAsyncFunction();
51
+ });
52
+
53
+ // 🚨 This will result in an your warn() call not taking effect
54
+ test('password', async () => {
55
+ await someAsyncFunction();
56
+
57
+ warn(); // 🚨
58
+ });
59
+
60
+ // 🚨 This will result in an your warn() call not taking effect
61
+ test('password', () => {
62
+ return anAsyncFunction().then(() => {
63
+ warn(); // 🚨
64
+ });
65
+ });
66
+ ```
67
+
68
+ ### Using warning in the result object
69
+
70
+ Just like you do with errors, you can access the errors in your validation warnings using these methods:
71
+
72
+ ```js
73
+ result.hasWarnings(); // Returns whether any warnings are present in the suite.
74
+ result.hasWarnings('password'); // Returns whether any warnings are present in the 'password' field.
75
+
76
+ result.getWarnings(); // Returns an object with all the fields that have warnings, and an array of warnings for each.
77
+ result.getWarnings('password'); // Returns an array of warnings for the password field.
78
+ ```
79
+
80
+ **Read next about:**
81
+
82
+ - [Vest's result object](./result).
package/enforce.d.ts ADDED
@@ -0,0 +1,230 @@
1
+ type EnforceExtendMap<T> = {
2
+ [K in keyof T]: (...args: any[]) => RuleReturn<T>;
3
+ };
4
+
5
+ interface IEnforceRunResult {
6
+ hasErrors?: boolean;
7
+ hasWarnings?: boolean;
8
+ message?: string;
9
+ warn?: boolean | void;
10
+ isArray?: boolean;
11
+ children?: {
12
+ [key: string]: IEnforceRunResult;
13
+ };
14
+ }
15
+
16
+ interface ILazy {
17
+ test: (...args: any[]) => boolean;
18
+ run: (...args: any[]) => IEnforceRunResult;
19
+ }
20
+
21
+ interface IEnforceTemplateReturn extends ILazy {
22
+ (value: any): IEnforceRules;
23
+ }
24
+
25
+ type RuleReturn<T> = IEnforceRules<T> & EnforceExtendMap<T>;
26
+
27
+ type TNumeral = number | string;
28
+ type RuleNumeral<T> = (expected: TNumeral) => RuleReturn<T>;
29
+ type RuleRange<T> = (start: TNumeral, end: TNumeral) => RuleReturn<T>;
30
+ type RuleNoExpectedValue<T> = () => RuleReturn<T>;
31
+ type RuleString<T> = (str: string) => RuleReturn<T>;
32
+ type RuleMatches<T> = (expected: string | RegExp) => RuleReturn<T>;
33
+ type RuleAny<T> = (expected: any) => RuleReturn<T>;
34
+ type RuleInside<T> = (
35
+ expected: Array<string | number | boolean> | string
36
+ ) => RuleReturn<T>;
37
+
38
+ type TLazyOrTemplate = TEnforceLazy | IEnforceTemplateReturn;
39
+
40
+ type CompoundListOfRules<T> = (...rules: TLazyOrTemplate[]) => RuleReturn<T>;
41
+ type TShapeObject = {
42
+ [key: string]: TLazyOrTemplate;
43
+ };
44
+ interface IEnforceRules<T = {}> {
45
+ [key: string]: (...args: any[]) => RuleReturn<T>;
46
+ equals: RuleAny<T>;
47
+ notEquals: RuleAny<T>;
48
+ numberEquals: RuleNumeral<T>;
49
+ greaterThan: RuleNumeral<T>;
50
+ greaterThanOrEquals: RuleNumeral<T>;
51
+ lessThan: RuleNumeral<T>;
52
+ lessThanOrEquals: RuleNumeral<T>;
53
+ longerThan: RuleNumeral<T>;
54
+ longerThanOrEquals: RuleNumeral<T>;
55
+ shorterThan: RuleNumeral<T>;
56
+ shorterThanOrEquals: RuleNumeral<T>;
57
+ gt: RuleNumeral<T>;
58
+ gte: RuleNumeral<T>;
59
+ lt: RuleNumeral<T>;
60
+ lte: RuleNumeral<T>;
61
+ isBetween: RuleRange<T>;
62
+ endsWith: RuleString<T>;
63
+ startsWith: RuleString<T>;
64
+ doesNotEndWith: RuleString<T>;
65
+ doesNotStartWith: RuleString<T>;
66
+ numberNotEquals: RuleNumeral<T>;
67
+ matches: RuleMatches<T>;
68
+ notMatches: RuleMatches<T>;
69
+ isUndefined: RuleNoExpectedValue<T>;
70
+ isArray: RuleNoExpectedValue<T>;
71
+ isEmpty: RuleNoExpectedValue<T>;
72
+ isEven: RuleNoExpectedValue<T>;
73
+ isBoolean: RuleNoExpectedValue<T>;
74
+ isNotBoolean: RuleNoExpectedValue<T>;
75
+ isNumber: RuleNoExpectedValue<T>;
76
+ isNaN: RuleNoExpectedValue<T>;
77
+ isNotNaN: RuleNoExpectedValue<T>;
78
+ isNull: RuleNoExpectedValue<T>;
79
+ isNotNull: RuleNoExpectedValue<T>;
80
+ isNumeric: RuleNoExpectedValue<T>;
81
+ isOdd: RuleNoExpectedValue<T>;
82
+ isTruthy: RuleNoExpectedValue<T>;
83
+ isFalsy: RuleNoExpectedValue<T>;
84
+ isString: RuleNoExpectedValue<T>;
85
+ isNotArray: RuleNoExpectedValue<T>;
86
+ isNotEmpty: RuleNoExpectedValue<T>;
87
+ isNotNumber: RuleNoExpectedValue<T>;
88
+ isNotNumeric: RuleNoExpectedValue<T>;
89
+ isNotBetween: RuleRange<T>;
90
+ isNotString: RuleNoExpectedValue<T>;
91
+ inside: RuleInside<T>;
92
+ notInside: RuleInside<T>;
93
+ lengthEquals: RuleNumeral<T>;
94
+ lengthNotEquals: RuleNumeral<T>;
95
+ isNegative: RuleNumeral<T>;
96
+ isPositive: RuleNumeral<T>;
97
+ loose: <T>(shape: TShapeObject) => RuleReturn<T>;
98
+ shape: <T>(
99
+ shape: TShapeObject,
100
+ options?: {
101
+ loose?: boolean;
102
+ }
103
+ ) => RuleReturn<T>;
104
+ isArrayOf: CompoundListOfRules<T>;
105
+ anyOf: CompoundListOfRules<T>;
106
+ allOf: CompoundListOfRules<T>;
107
+ oneOf: CompoundListOfRules<T>;
108
+ }
109
+
110
+ interface IEnforce {
111
+ /**
112
+ * Assertion function. Throws an error on failure.
113
+ * @param value Value being enforced
114
+ */
115
+ (value: any): IEnforceRules;
116
+
117
+ /**
118
+ * Adds custom rules to enforce
119
+ * @param rules Rules object to add onto enforce
120
+ *
121
+ * @example
122
+ *
123
+ * const customEnforce = enforce.extend({
124
+ * isValidEmail: (email) => email.includes('@')
125
+ * });
126
+ *
127
+ * customEnforce('notAnEmail') // throws an error
128
+ */
129
+ extend<
130
+ T extends {
131
+ [key: string]: (
132
+ value: any,
133
+ ...args: any[]
134
+ ) =>
135
+ | boolean
136
+ | {
137
+ pass: boolean;
138
+ message?: string | (() => string);
139
+ };
140
+ }
141
+ >(
142
+ obj: T
143
+ ): (value: any) => IEnforceRules<T> & EnforceExtendMap<T>;
144
+
145
+ template: (...rules: Array<TLazyOrTemplate>) => IEnforceTemplateReturn;
146
+ }
147
+
148
+ type LazyNumeral = (expected: TNumeral) => TEnforceLazyReturn;
149
+ type LazyEnforceWithNoArgs = () => TEnforceLazyReturn;
150
+ type LazyString = (str: string) => TEnforceLazyReturn;
151
+ type LazyRange = (start: number, end: number) => TEnforceLazyReturn;
152
+ type LazyMatches = (expected: string | RegExp) => TEnforceLazyReturn;
153
+ type LazyAny = (expected: any) => TEnforceLazyReturn;
154
+ type LazyInside = (
155
+ expected: Array<string | number | boolean> | string
156
+ ) => TEnforceLazyReturn;
157
+ type LazyCopmoundListOfRules = <T>(
158
+ ...rules: TLazyOrTemplate[]
159
+ ) => TEnforceLazyReturn;
160
+
161
+ type TEnforceLazyReturn = TEnforceLazy & ILazy;
162
+
163
+ type TEnforceLazy = {
164
+ [key: string]: (...args: any[]) => TEnforceLazyReturn;
165
+ equals: LazyAny;
166
+ notEquals: LazyAny;
167
+ numberEquals: LazyNumeral;
168
+ greaterThan: LazyNumeral;
169
+ greaterThanOrEquals: LazyNumeral;
170
+ lessThan: LazyNumeral;
171
+ lessThanOrEquals: LazyNumeral;
172
+ longerThan: LazyNumeral;
173
+ longerThanOrEquals: LazyNumeral;
174
+ shorterThan: LazyNumeral;
175
+ shorterThanOrEquals: LazyNumeral;
176
+ gt: LazyNumeral;
177
+ gte: LazyNumeral;
178
+ lt: LazyNumeral;
179
+ lte: LazyNumeral;
180
+ isBetween: LazyRange;
181
+ endsWith: LazyString;
182
+ startsWith: LazyString;
183
+ doesNotEndWith: LazyString;
184
+ doesNotStartWith: LazyString;
185
+ numberNotEquals: LazyNumeral;
186
+ matches: LazyMatches;
187
+ notMatches: LazyMatches;
188
+ isUndefined: LazyEnforceWithNoArgs;
189
+ isArray: LazyEnforceWithNoArgs;
190
+ isEmpty: LazyEnforceWithNoArgs;
191
+ isEven: LazyEnforceWithNoArgs;
192
+ isNumber: LazyEnforceWithNoArgs;
193
+ isNaN: LazyEnforceWithNoArgs;
194
+ isNotNaN: LazyEnforceWithNoArgs;
195
+ isNull: LazyEnforceWithNoArgs;
196
+ isNotNull: LazyEnforceWithNoArgs;
197
+ isNumeric: LazyEnforceWithNoArgs;
198
+ isOdd: LazyEnforceWithNoArgs;
199
+ isTruthy: LazyEnforceWithNoArgs;
200
+ isFalsy: LazyEnforceWithNoArgs;
201
+ isString: LazyEnforceWithNoArgs;
202
+ isNotArray: LazyEnforceWithNoArgs;
203
+ isNotEmpty: LazyEnforceWithNoArgs;
204
+ isNotNumber: LazyEnforceWithNoArgs;
205
+ isNotNumeric: LazyEnforceWithNoArgs;
206
+ isNotBetween: LazyRange;
207
+ isNotString: LazyEnforceWithNoArgs;
208
+ inside: LazyInside;
209
+ notInside: LazyInside;
210
+ lengthEquals: LazyNumeral;
211
+ lengthNotEquals: LazyNumeral;
212
+ isNegative: LazyEnforceWithNoArgs;
213
+ isPositive: LazyEnforceWithNoArgs;
214
+ isBoolean: LazyEnforceWithNoArgs;
215
+ isNotBoolean: LazyEnforceWithNoArgs;
216
+ loose: <T>(shape: TShapeObject) => TEnforceLazyReturn;
217
+ shape: <T>(
218
+ shape: TShapeObject,
219
+ options?: {
220
+ loose?: boolean;
221
+ }
222
+ ) => TEnforceLazyReturn;
223
+ optional: LazyCopmoundListOfRules;
224
+ isArrayOf: LazyCopmoundListOfRules;
225
+ anyOf: LazyCopmoundListOfRules;
226
+ allOf: LazyCopmoundListOfRules;
227
+ oneOf: LazyCopmoundListOfRules;
228
+ };
229
+
230
+ export type TEnforce = IEnforce & TEnforceLazyReturn;
@@ -0,0 +1 @@
1
+ {"type":"module"}