UNPKG

15.5 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/builtin/interopRequireDefault");
4
5exports.__esModule = true;
6exports.default = SchemaType;
7
8var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/builtin/extends"));
9
10var _has = _interopRequireDefault(require("lodash/has"));
11
12var _cloneDeepWith = _interopRequireDefault(require("lodash/cloneDeepWith"));
13
14var _toArray2 = _interopRequireDefault(require("lodash/toArray"));
15
16var _locale = require("./locale");
17
18var _Condition = _interopRequireDefault(require("./Condition"));
19
20var _runValidations = _interopRequireDefault(require("./util/runValidations"));
21
22var _merge = _interopRequireDefault(require("./util/merge"));
23
24var _isSchema = _interopRequireDefault(require("./util/isSchema"));
25
26var _isAbsent = _interopRequireDefault(require("./util/isAbsent"));
27
28var _createValidation = _interopRequireDefault(require("./util/createValidation"));
29
30var _printValue = _interopRequireDefault(require("./util/printValue"));
31
32var _Reference = _interopRequireDefault(require("./Reference"));
33
34var _reach = require("./util/reach");
35
36var notEmpty = function notEmpty(value) {
37 return !(0, _isAbsent.default)(value);
38};
39
40var RefSet =
41/*#__PURE__*/
42function () {
43 function RefSet() {
44 this.list = new Set();
45 this.refs = new Map();
46 }
47
48 var _proto = RefSet.prototype;
49
50 _proto.toArray = function toArray() {
51 return (0, _toArray2.default)(this.list).concat((0, _toArray2.default)(this.refs.values()));
52 };
53
54 _proto.add = function add(value) {
55 _Reference.default.isRef(value) ? this.refs.set(value.key, value) : this.list.add(value);
56 };
57
58 _proto.delete = function _delete(value) {
59 _Reference.default.isRef(value) ? this.refs.delete(value.key, value) : this.list.delete(value);
60 };
61
62 _proto.has = function has(value, resolve) {
63 if (this.list.has(value)) return true;
64 var item,
65 values = this.refs.values();
66
67 while (item = values.next(), !item.done) {
68 if (resolve(item.value) === value) return true;
69 }
70
71 return false;
72 };
73
74 return RefSet;
75}();
76
77function SchemaType(options) {
78 var _this = this;
79
80 if (options === void 0) {
81 options = {};
82 }
83
84 if (!(this instanceof SchemaType)) return new SchemaType();
85 this._deps = [];
86 this._conditions = [];
87 this._options = {
88 abortEarly: true,
89 recursive: true
90 };
91 this._exclusive = Object.create(null);
92 this._whitelist = new RefSet();
93 this._blacklist = new RefSet();
94 this.tests = [];
95 this.transforms = [];
96 this.withMutation(function () {
97 _this.typeError(_locale.mixed.notType);
98 });
99 if ((0, _has.default)(options, 'default')) this._defaultDefault = options.default;
100 this._type = options.type || 'mixed';
101}
102
103var proto = SchemaType.prototype = {
104 __isYupSchema__: true,
105 constructor: SchemaType,
106 clone: function clone() {
107 var _this2 = this;
108
109 if (this._mutate) return this; // if the nested value is a schema we can skip cloning, since
110 // they are already immutable
111
112 return (0, _cloneDeepWith.default)(this, function (value) {
113 if ((0, _isSchema.default)(value) && value !== _this2) return value;
114 });
115 },
116 label: function label(_label) {
117 var next = this.clone();
118 next._label = _label;
119 return next;
120 },
121 meta: function meta(obj) {
122 if (arguments.length === 0) return this._meta;
123 var next = this.clone();
124 next._meta = (0, _extends2.default)(next._meta || {}, obj);
125 return next;
126 },
127 withMutation: function withMutation(fn) {
128 this._mutate = true;
129 var result = fn(this);
130 this._mutate = false;
131 return result;
132 },
133 concat: function concat(schema) {
134 if (!schema) return this;
135 if (schema._type !== this._type && this._type !== 'mixed') throw new TypeError("You cannot `concat()` schema's of different types: " + this._type + " and " + schema._type);
136 var cloned = this.clone();
137 var next = (0, _merge.default)(this.clone(), schema.clone()); // undefined isn't merged over, but is a valid value for default
138
139 if ((0, _has.default)(schema, '_default')) next._default = schema._default;
140 next.tests = cloned.tests;
141 next._exclusive = cloned._exclusive; // manually add the new tests to ensure
142 // the deduping logic is consistent
143
144 schema.tests.forEach(function (fn) {
145 next = next.test(fn.TEST);
146 });
147 next._type = schema._type;
148 return next;
149 },
150 isType: function isType(v) {
151 if (this._nullable && v === null) return true;
152 return !this._typeCheck || this._typeCheck(v);
153 },
154 resolve: function resolve(_ref) {
155 var context = _ref.context,
156 parent = _ref.parent;
157
158 if (this._conditions.length) {
159 return this._conditions.reduce(function (schema, match) {
160 return match.resolve(schema, match.getValue(parent, context));
161 }, this);
162 }
163
164 return this;
165 },
166 cast: function cast(value, options) {
167 if (options === void 0) {
168 options = {};
169 }
170
171 var resolvedSchema = this.resolve(options);
172
173 var result = resolvedSchema._cast(value, options);
174
175 if (value !== undefined && options.assert !== false && resolvedSchema.isType(result) !== true) {
176 var formattedValue = (0, _printValue.default)(value);
177 var formattedResult = (0, _printValue.default)(result);
178 throw new TypeError("The value of " + (options.path || 'field') + " could not be cast to a value " + ("that satisfies the schema type: \"" + resolvedSchema._type + "\". \n\n") + ("attempted value: " + formattedValue + " \n") + (formattedResult !== formattedValue ? "result of cast: " + formattedResult : ''));
179 }
180
181 return result;
182 },
183 _cast: function _cast(rawValue) {
184 var _this3 = this;
185
186 var value = rawValue === undefined ? rawValue : this.transforms.reduce(function (value, fn) {
187 return fn.call(_this3, value, rawValue);
188 }, rawValue);
189
190 if (value === undefined && (0, _has.default)(this, '_default')) {
191 value = this.default();
192 }
193
194 return value;
195 },
196 _validate: function _validate(_value, options) {
197 var _this4 = this;
198
199 if (options === void 0) {
200 options = {};
201 }
202
203 var value = _value;
204 var originalValue = options.originalValue != null ? options.originalValue : _value;
205
206 var isStrict = this._option('strict', options);
207
208 var endEarly = this._option('abortEarly', options);
209
210 var sync = options.sync;
211 var path = options.path;
212 var label = this._label;
213
214 if (!isStrict) {
215 value = this._cast(value, (0, _extends2.default)({
216 assert: false
217 }, options));
218 } // value is cast, we can check if it meets type requirements
219
220
221 var validationParams = {
222 value: value,
223 path: path,
224 schema: this,
225 options: options,
226 label: label,
227 originalValue: originalValue,
228 sync: sync
229 };
230 var initialTests = [];
231 if (this._typeError) initialTests.push(this._typeError(validationParams));
232 if (this._whitelistError) initialTests.push(this._whitelistError(validationParams));
233 if (this._blacklistError) initialTests.push(this._blacklistError(validationParams));
234 return (0, _runValidations.default)({
235 validations: initialTests,
236 endEarly: endEarly,
237 value: value,
238 path: path,
239 sync: sync
240 }).then(function (value) {
241 return (0, _runValidations.default)({
242 path: path,
243 sync: sync,
244 value: value,
245 endEarly: endEarly,
246 validations: _this4.tests.map(function (fn) {
247 return fn(validationParams);
248 })
249 });
250 });
251 },
252 validate: function validate(value, options) {
253 if (options === void 0) {
254 options = {};
255 }
256
257 var schema = this.resolve(options);
258 return schema._validate(value, options);
259 },
260 validateSync: function validateSync(value, options) {
261 if (options === void 0) {
262 options = {};
263 }
264
265 var schema = this.resolve(options);
266 var result, err;
267
268 schema._validate(value, (0, _extends2.default)({}, options, {
269 sync: true
270 })).then(function (r) {
271 return result = r;
272 }).catch(function (e) {
273 return err = e;
274 });
275
276 if (err) throw err;
277 return result;
278 },
279 isValid: function isValid(value, options) {
280 return this.validate(value, options).then(function () {
281 return true;
282 }).catch(function (err) {
283 if (err.name === 'ValidationError') return false;
284 throw err;
285 });
286 },
287 isValidSync: function isValidSync(value, options) {
288 try {
289 this.validateSync(value, (0, _extends2.default)({}, options));
290 return true;
291 } catch (err) {
292 if (err.name === 'ValidationError') return false;
293 throw err;
294 }
295 },
296 getDefault: function getDefault(options) {
297 if (options === void 0) {
298 options = {};
299 }
300
301 var schema = this.resolve(options);
302 return schema.default();
303 },
304 default: function _default(def) {
305 if (arguments.length === 0) {
306 var defaultValue = (0, _has.default)(this, '_default') ? this._default : this._defaultDefault;
307 return typeof defaultValue === 'function' ? defaultValue.call(this) : (0, _cloneDeepWith.default)(defaultValue);
308 }
309
310 var next = this.clone();
311 next._default = def;
312 return next;
313 },
314 strict: function strict() {
315 var next = this.clone();
316 next._options.strict = true;
317 return next;
318 },
319 required: function required(message) {
320 if (message === void 0) {
321 message = _locale.mixed.required;
322 }
323
324 return this.test({
325 message: message,
326 name: 'required',
327 test: notEmpty
328 });
329 },
330 notRequired: function notRequired() {
331 var next = this.clone();
332 next.tests = next.tests.filter(function (test) {
333 return test.TEST_NAME !== 'required';
334 });
335 return next;
336 },
337 nullable: function nullable(value) {
338 var next = this.clone();
339 next._nullable = value === false ? false : true;
340 return next;
341 },
342 transform: function transform(fn) {
343 var next = this.clone();
344 next.transforms.push(fn);
345 return next;
346 },
347
348 /**
349 * Adds a test function to the schema's queue of tests.
350 * tests can be exclusive or non-exclusive.
351 *
352 * - exclusive tests, will replace any existing tests of the same name.
353 * - non-exclusive: can be stacked
354 *
355 * If a non-exclusive test is added to a schema with an exclusive test of the same name
356 * the exclusive test is removed and further tests of the same name will be stacked.
357 *
358 * If an exclusive test is added to a schema with non-exclusive tests of the same name
359 * the previous tests are removed and further tests of the same name will replace each other.
360 */
361 test: function test() {
362 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
363 args[_key] = arguments[_key];
364 }
365
366 var opts = args[0];
367
368 if (args.length > 1) {
369 var name = args[0],
370 message = args[1],
371 test = args[2];
372
373 if (test == null) {
374 test = message;
375 message = _locale.mixed.default;
376 }
377
378 opts = {
379 name: name,
380 test: test,
381 message: message,
382 exclusive: false
383 };
384 }
385
386 if (typeof opts.test !== 'function') throw new TypeError('`test` is a required parameters');
387 var next = this.clone();
388 var validate = (0, _createValidation.default)(opts);
389 var isExclusive = opts.exclusive || opts.name && next._exclusive[opts.name] === true;
390
391 if (opts.exclusive && !opts.name) {
392 throw new TypeError('Exclusive tests must provide a unique `name` identifying the test');
393 }
394
395 next._exclusive[opts.name] = !!opts.exclusive;
396 next.tests = next.tests.filter(function (fn) {
397 if (fn.TEST_NAME === opts.name) {
398 if (isExclusive) return false;
399 if (fn.TEST.test === validate.TEST.test) return false;
400 }
401
402 return true;
403 });
404 next.tests.push(validate);
405 return next;
406 },
407 when: function when(keys, options) {
408 var next = this.clone(),
409 deps = [].concat(keys).map(function (key) {
410 return new _Reference.default(key);
411 });
412 deps.forEach(function (dep) {
413 if (!dep.isContext) next._deps.push(dep.key);
414 });
415
416 next._conditions.push(new _Condition.default(deps, options));
417
418 return next;
419 },
420 typeError: function typeError(message) {
421 var next = this.clone();
422 next._typeError = (0, _createValidation.default)({
423 message: message,
424 name: 'typeError',
425 test: function test(value) {
426 if (value !== undefined && !this.schema.isType(value)) return this.createError({
427 params: {
428 type: this.schema._type
429 }
430 });
431 return true;
432 }
433 });
434 return next;
435 },
436 oneOf: function oneOf(enums, message) {
437 if (message === void 0) {
438 message = _locale.mixed.oneOf;
439 }
440
441 var next = this.clone();
442 enums.forEach(function (val) {
443 next._whitelist.add(val);
444
445 next._blacklist.delete(val);
446 });
447 next._whitelistError = (0, _createValidation.default)({
448 message: message,
449 name: 'oneOf',
450 test: function test(value) {
451 if (value === undefined) return true;
452 var valids = this.schema._whitelist;
453 return valids.has(value, this.resolve) ? true : this.createError({
454 params: {
455 values: valids.toArray().join(', ')
456 }
457 });
458 }
459 });
460 return next;
461 },
462 notOneOf: function notOneOf(enums, message) {
463 if (message === void 0) {
464 message = _locale.mixed.notOneOf;
465 }
466
467 var next = this.clone();
468 enums.forEach(function (val) {
469 next._blacklist.add(val);
470
471 next._whitelist.delete(val);
472 });
473 next._blacklistError = (0, _createValidation.default)({
474 message: message,
475 name: 'notOneOf',
476 test: function test(value) {
477 var invalids = this.schema._blacklist;
478 if (invalids.has(value, this.resolve)) return this.createError({
479 params: {
480 values: invalids.toArray().join(', ')
481 }
482 });
483 return true;
484 }
485 });
486 return next;
487 },
488 strip: function strip(_strip) {
489 if (_strip === void 0) {
490 _strip = true;
491 }
492
493 var next = this.clone();
494 next._strip = _strip;
495 return next;
496 },
497 _option: function _option(key, overrides) {
498 return (0, _has.default)(overrides, key) ? overrides[key] : this._options[key];
499 },
500 describe: function describe() {
501 var next = this.clone();
502 return {
503 type: next._type,
504 meta: next._meta,
505 label: next._label,
506 tests: next.tests.map(function (fn) {
507 return fn.TEST_NAME;
508 }, {}).filter(function (n, idx, list) {
509 return list.indexOf(n) === idx;
510 })
511 };
512 }
513};
514var _arr = ['validate', 'validateSync'];
515
516var _loop = function _loop() {
517 var method = _arr[_i];
518
519 proto[method + "At"] = function (path, value, options) {
520 if (options === void 0) {
521 options = {};
522 }
523
524 var _getIn = (0, _reach.getIn)(this, path, value, options.context),
525 parent = _getIn.parent,
526 parentPath = _getIn.parentPath,
527 schema = _getIn.schema;
528
529 return schema[method](parent[parentPath], (0, _extends2.default)({}, options, {
530 parent: parent,
531 path: parentPath
532 }));
533 };
534};
535
536for (var _i = 0; _i < _arr.length; _i++) {
537 _loop();
538}
539
540var _arr2 = ['equals', 'is'];
541
542for (var _i2 = 0; _i2 < _arr2.length; _i2++) {
543 var alias = _arr2[_i2];
544 proto[alias] = proto.oneOf;
545}
546
547var _arr3 = ['not', 'nope'];
548
549for (var _i3 = 0; _i3 < _arr3.length; _i3++) {
550 var _alias = _arr3[_i3];
551 proto[_alias] = proto.notOneOf;
552}
553
554module.exports = exports["default"];
\No newline at end of file