-
-
Notifications
You must be signed in to change notification settings - Fork 173
/
validator.js
232 lines (227 loc) · 6.61 KB
/
validator.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
import { isNone } from '@ember/utils';
import { deprecate } from '@ember/application/deprecations';
/**
* @module Validators
* @main Validators
*/
/**
* ### description
*
* Default: __'This field'__
*
* A descriptor for your attribute used in the error message strings.
* You can overwrite this value in your `validators/messages.js` file by changing the `defaultDescription` property.
*
* ```javascript
* // Examples
* validator('date', {
* description: 'Date of birth'
* })
* // If validation is run and the attribute is empty, the error returned will be:
* // 'Date of birth can't be blank'
* ```
*
* ### lazy
*
* Default: __true__
*
* Only validate the given validator if the attribute is not already in an invalid
* state. When you have multiple validators on an attribute, it will only validate subsequent
* validators if the preceding validators have passed. When set to __false__, the validator
* will always be executed, even if its preceding validators are invalid.
*
* ```javascript
* // Examples
* buildValidations({
* username: [
* validator('presence', true),
* validator('length', { min: 5 }),
* validator('custom-promise-based-validator') // Will only be executed if the above two have passed
* ]
* });
*
* validator('custom-validator-that-must-executed', {
* lazy: false
* })
* ```
*
* ### dependentKeys
*
* A list of other model specific dependents for you validator.
*
* ```javascript
* // Examples
* validator('has-friends', {
* dependentKeys: ['model.friends.[]']
* })
* validator('has-valid-friends', {
* dependentKeys: ['model.friends.@each.username']
* })
* validator('x-validator', {
* dependentKeys: ['model.username', 'model.email', 'model.meta.foo.bar']
* })
* ```
*
* ### disabled
*
* Default: __false__
*
* If set to __true__, disables the given validator.
*
* ```js
* // Examples
* validator('presence', {
* presence: true,
* disabled: true
* })
* validator('presence', {
* presence: true,
* disabled: computed.not('model.shouldValidate')
* })
* ```
*
* ### debounce
*
* Default: __0__
*
* Debounces the validation with the given time in `milliseconds`. All debounced validations will
* be handled asynchronously (wrapped in a promise).
*
* ```javascript
* // Examples
* validator('length', {
* debounce: 500
* })
* validator('x-validator', {
* debounce: 250
* })
* ```
*
* ### isWarning
*
* Default: __false__
*
* Any validator can be declared as a warning validator by setting `isWarning` to true. These validators will act as
* assertions that when return a message, will be placed under `warnings` and `warningMessages` collections. What this means,
* is that these validators will not have any affect on the valid state of the attribute allowing you to display warning messages
* even when the attribute is valid.
*
* ```javascript
* // Examples
* validator('length', {
* isWarning: true,
* min: 6,
* message: 'Password is weak'
* })
* ```
*
* ### volatile
*
* Default: __false__
*
* If any validator sets the volatile option to **true** (including options, default options, and global options),
* it will place the entire attribute's CP in a volatile state. This means that it will set it into non-cached mode.
* When in this mode the computed property will not automatically cache the return value.
*
* Dependency keys have no effect on volatile properties as they are for cache invalidation and notification when
* cached value is invalidated. Any changes to the dependents will not refire validations.
*
* __**WARNING: This option should only be used if you know what you're doing**__
*
* ```javascript
* // Examples
* validator('length', {
* volatile: true
* })
* ```
*
* ### value
*
* Used to retrieve the value to validate. This will overwrite the validator's default `value` method.
* By default this returns `model[attribute]`. If you are dependent on other model attributes, you will
* need to add them as `dependentKeys`.
*
* ```javascript
* // Examples
* validator('date', {
* value(model, attribute) {
* // Format the original value before passing it into the validator
* return moment().utc(model.get(attribute)).format('DD/MM/YYY');
* }
* })
* validator('number', {
* dependentKeys: ['someOtherAttr'],
* value(model, attribute) {
* // Validate a value that is not the current attribute
* return this.get('model').get('someOtherAttr');
* }
* })
* ```
*
* ### message
*
* This option can take two forms. It can either be a `string` (a CP that returns a string is also valid), or a `function`.
* If a string is used, then it will overwrite all error message types for the specified validator.
*
* ```javascript
* // Example: String
* validator('confirmation', {
* message: 'Email does not match {attribute}. What are you even thinking?!'
* })
* ```
*
* We can pass a `function` into our message option for even more customization capabilities.
*
* ```javascript
* // Example: Function
* validator('date', {
* message(type, options, value, context) {
* if (type === 'before') {
* return '{description} should really be before {date}';
* }
* if (type === 'after') {
* return '{description} should really be after {date}';
* }
* }
* })
* ```
* The message function is given the following arguments:
*
* - `type` (**String**): The error message type
* - `options` (**Object**): The validator options that were defined in the model
* - `value`: The current value being evaluated
* - `context` (**Object**): Context for string replacement
*
* The return value must be a `string`. If nothing is returned (`undefined`),
* defaults to the default error message of the specified type.
*
* Within this function, the context is set to that of the current validator.
* This gives you access to the model, defaultMessages, options and more.
*
*
* @module Validators
* @submodule Common Options
*/
export default function(arg1, options) {
let props = {
options: isNone(options) ? {} : options
};
if (typeof arg1 === 'function') {
deprecate(
'[ember-cp-validations] `validator` no longer directly accepts ' +
'a function. Please use the inline validator syntax:' +
"\n\nvalidator('inline', { validate() {} )\n\n",
false,
{ id: 'ember-cp-validations.inline-validator', until: '4.2.0' }
);
props.options.validate = arg1;
props._type = 'inline';
} else if (typeof arg1 === 'string') {
props._type = arg1;
} else {
throw new TypeError(
'[ember-cp-validations] Unexpected type for first validator argument — It must be a string.'
);
}
return props;
}