UNPKG

20 kBJavaScriptView Raw
1import _extends from "@babel/runtime/helpers/esm/extends";
2import _createClass from "@babel/runtime/helpers/esm/createClass";
3
4function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } it = o[Symbol.iterator](); return it.next.bind(it); }
5
6function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
7
8function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
9
10import has from "lodash-es/has";
11import cloneDeepWith from "lodash-es/cloneDeepWith";
12import _toArray from "lodash-es/toArray";
13import { mixed as locale } from './locale';
14import Condition from './Condition';
15import runTests from './util/runTests';
16import prependDeep from './util/prependDeep';
17import isSchema from './util/isSchema';
18import createValidation from './util/createValidation';
19import printValue from './util/printValue';
20import Ref from './Reference';
21import { getIn } from './util/reach';
22
23var RefSet = /*#__PURE__*/function () {
24 function RefSet() {
25 this.list = new Set();
26 this.refs = new Map();
27 }
28
29 var _proto = RefSet.prototype;
30
31 _proto.describe = function describe() {
32 var description = [];
33
34 for (var _iterator = _createForOfIteratorHelperLoose(this.list), _step; !(_step = _iterator()).done;) {
35 var item = _step.value;
36 description.push(item);
37 }
38
39 for (var _iterator2 = _createForOfIteratorHelperLoose(this.refs), _step2; !(_step2 = _iterator2()).done;) {
40 var _step2$value = _step2.value,
41 ref = _step2$value[1];
42 description.push(ref.describe());
43 }
44
45 return description;
46 };
47
48 _proto.toArray = function toArray() {
49 return _toArray(this.list).concat(_toArray(this.refs.values()));
50 };
51
52 _proto.add = function add(value) {
53 Ref.isRef(value) ? this.refs.set(value.key, value) : this.list.add(value);
54 };
55
56 _proto.delete = function _delete(value) {
57 Ref.isRef(value) ? this.refs.delete(value.key) : this.list.delete(value);
58 };
59
60 _proto.has = function has(value, resolve) {
61 if (this.list.has(value)) return true;
62 var item,
63 values = this.refs.values();
64
65 while (item = values.next(), !item.done) {
66 if (resolve(item.value) === value) return true;
67 }
68
69 return false;
70 };
71
72 _proto.clone = function clone() {
73 var next = new RefSet();
74 next.list = new Set(this.list);
75 next.refs = new Map(this.refs);
76 return next;
77 };
78
79 _proto.merge = function merge(newItems, removeItems) {
80 var next = this.clone();
81 newItems.list.forEach(function (value) {
82 return next.add(value);
83 });
84 newItems.refs.forEach(function (value) {
85 return next.add(value);
86 });
87 removeItems.list.forEach(function (value) {
88 return next.delete(value);
89 });
90 removeItems.refs.forEach(function (value) {
91 return next.delete(value);
92 });
93 return next;
94 };
95
96 _createClass(RefSet, [{
97 key: "size",
98 get: function get() {
99 return this.list.size + this.refs.size;
100 }
101 }]);
102
103 return RefSet;
104}();
105
106export default function SchemaType(options) {
107 var _this = this;
108
109 if (options === void 0) {
110 options = {};
111 }
112
113 if (!(this instanceof SchemaType)) return new SchemaType();
114 this._deps = [];
115 this._conditions = [];
116 this._options = {
117 abortEarly: true,
118 recursive: true
119 };
120 this._exclusive = Object.create(null);
121 this._whitelist = new RefSet();
122 this._blacklist = new RefSet();
123 this.tests = [];
124 this.transforms = [];
125 this.withMutation(function () {
126 _this.typeError(locale.notType);
127 });
128 if (has(options, 'default')) this._defaultDefault = options.default;
129 this.type = options.type || 'mixed'; // TODO: remove
130
131 this._type = options.type || 'mixed';
132}
133var proto = SchemaType.prototype = {
134 __isYupSchema__: true,
135 constructor: SchemaType,
136 clone: function clone() {
137 var _this2 = this;
138
139 if (this._mutate) return this; // if the nested value is a schema we can skip cloning, since
140 // they are already immutable
141
142 return cloneDeepWith(this, function (value, key) {
143 if (isSchema(value) && value !== _this2) return value; // fix for ie11 when cloning Set and Map
144
145 if (key === '_whitelist' || key === '_blacklist') {
146 return value.clone();
147 }
148 });
149 },
150 label: function label(_label) {
151 var next = this.clone();
152 next._label = _label;
153 return next;
154 },
155 meta: function meta(obj) {
156 if (arguments.length === 0) return this._meta;
157 var next = this.clone();
158 next._meta = _extends(next._meta || {}, obj);
159 return next;
160 },
161 withMutation: function withMutation(fn) {
162 var before = this._mutate;
163 this._mutate = true;
164 var result = fn(this);
165 this._mutate = before;
166 return result;
167 },
168 concat: function concat(schema) {
169 if (!schema || schema === this) return this;
170 if (schema._type !== this._type && this._type !== 'mixed') throw new TypeError("You cannot `concat()` schema's of different types: " + this._type + " and " + schema._type);
171 var next = prependDeep(schema.clone(), this); // new undefined default is overridden by old non-undefined one, revert
172
173 if (has(schema, '_default')) next._default = schema._default;
174 next.tests = this.tests;
175 next._exclusive = this._exclusive; // manually merge the blacklist/whitelist (the other `schema` takes
176 // precedence in case of conflicts)
177
178 next._whitelist = this._whitelist.merge(schema._whitelist, schema._blacklist);
179 next._blacklist = this._blacklist.merge(schema._blacklist, schema._whitelist); // manually add the new tests to ensure
180 // the deduping logic is consistent
181
182 next.withMutation(function (next) {
183 schema.tests.forEach(function (fn) {
184 next.test(fn.OPTIONS);
185 });
186 });
187 return next;
188 },
189 isType: function isType(v) {
190 if (this._nullable && v === null) return true;
191 return !this._typeCheck || this._typeCheck(v);
192 },
193 resolve: function resolve(options) {
194 var schema = this;
195
196 if (schema._conditions.length) {
197 var conditions = schema._conditions;
198 schema = schema.clone();
199 schema._conditions = [];
200 schema = conditions.reduce(function (schema, condition) {
201 return condition.resolve(schema, options);
202 }, schema);
203 schema = schema.resolve(options);
204 }
205
206 return schema;
207 },
208
209 /**
210 *
211 * @param {*} value
212 * @param {Object} options
213 * @param {*=} options.parent
214 * @param {*=} options.context
215 */
216 cast: function cast(value, options) {
217 if (options === void 0) {
218 options = {};
219 }
220
221 var resolvedSchema = this.resolve(_extends({
222 value: value
223 }, options));
224
225 var result = resolvedSchema._cast(value, options);
226
227 if (value !== undefined && options.assert !== false && resolvedSchema.isType(result) !== true) {
228 var formattedValue = printValue(value);
229 var formattedResult = printValue(result);
230 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 : ''));
231 }
232
233 return result;
234 },
235 _cast: function _cast(rawValue) {
236 var _this3 = this;
237
238 var value = rawValue === undefined ? rawValue : this.transforms.reduce(function (value, fn) {
239 return fn.call(_this3, value, rawValue);
240 }, rawValue);
241
242 if (value === undefined && has(this, '_default')) {
243 value = this.getDefault();
244 }
245
246 return value;
247 },
248 _validate: function _validate(_value, options, cb) {
249 var _this4 = this;
250
251 if (options === void 0) {
252 options = {};
253 }
254
255 var _options = options,
256 sync = _options.sync,
257 path = _options.path,
258 _options$from = _options.from,
259 from = _options$from === void 0 ? [] : _options$from,
260 _options$originalValu = _options.originalValue,
261 originalValue = _options$originalValu === void 0 ? _value : _options$originalValu,
262 _options$strict = _options.strict,
263 strict = _options$strict === void 0 ? this._options.strict : _options$strict,
264 _options$abortEarly = _options.abortEarly,
265 abortEarly = _options$abortEarly === void 0 ? this._options.abortEarly : _options$abortEarly;
266 var value = _value;
267
268 if (!strict) {
269 this._validating = true;
270 value = this._cast(value, _extends({
271 assert: false
272 }, options));
273 this._validating = false;
274 } // value is cast, we can check if it meets type requirements
275
276
277 var args = {
278 value: value,
279 path: path,
280 options: options,
281 originalValue: originalValue,
282 schema: this,
283 label: this._label,
284 sync: sync,
285 from: from
286 };
287 var initialTests = [];
288 if (this._typeError) initialTests.push(this._typeError);
289 if (this._whitelistError) initialTests.push(this._whitelistError);
290 if (this._blacklistError) initialTests.push(this._blacklistError);
291 return runTests({
292 args: args,
293 value: value,
294 path: path,
295 sync: sync,
296 tests: initialTests,
297 endEarly: abortEarly
298 }, function (err) {
299 if (err) return void cb(err);
300 runTests({
301 tests: _this4.tests,
302 args: args,
303 path: path,
304 sync: sync,
305 value: value,
306 endEarly: abortEarly
307 }, cb);
308 });
309 },
310 validate: function validate(value, options, maybeCb) {
311 if (options === void 0) {
312 options = {};
313 }
314
315 var schema = this.resolve(_extends({}, options, {
316 value: value
317 })); // callback case is for nested validations
318
319 return typeof maybeCb === 'function' ? schema._validate(value, options, maybeCb) : new Promise(function (resolve, reject) {
320 return schema._validate(value, options, function (err, value) {
321 if (err) reject(err);else resolve(value);
322 });
323 });
324 },
325 validateSync: function validateSync(value, options) {
326 if (options === void 0) {
327 options = {};
328 }
329
330 var schema = this.resolve(_extends({}, options, {
331 value: value
332 }));
333 var result;
334
335 schema._validate(value, _extends({}, options, {
336 sync: true
337 }), function (err, value) {
338 if (err) throw err;
339 result = value;
340 });
341
342 return result;
343 },
344 isValid: function isValid(value, options) {
345 return this.validate(value, options).then(function () {
346 return true;
347 }).catch(function (err) {
348 if (err.name === 'ValidationError') return false;
349 throw err;
350 });
351 },
352 isValidSync: function isValidSync(value, options) {
353 try {
354 this.validateSync(value, options);
355 return true;
356 } catch (err) {
357 if (err.name === 'ValidationError') return false;
358 throw err;
359 }
360 },
361 _getDefault: function _getDefault() {
362 var defaultValue = has(this, '_default') ? this._default : this._defaultDefault;
363 return typeof defaultValue === 'function' ? defaultValue.call(this) : cloneDeepWith(defaultValue);
364 },
365 getDefault: function getDefault(options) {
366 if (options === void 0) {
367 options = {};
368 }
369
370 var schema = this.resolve(options);
371 return schema._getDefault();
372 },
373 default: function _default(def) {
374 if (arguments.length === 0) {
375 console.warn('Calling `schema.default()` as a getter to retrieve a default is deprecated and will be removed in the next version. \n' + 'Use `schema.getDefault()` instead.');
376 return this._getDefault();
377 }
378
379 var next = this.clone();
380 next._default = def;
381 return next;
382 },
383 strict: function strict(isStrict) {
384 if (isStrict === void 0) {
385 isStrict = true;
386 }
387
388 var next = this.clone();
389 next._options.strict = isStrict;
390 return next;
391 },
392 _isPresent: function _isPresent(value) {
393 return value != null;
394 },
395 required: function required(message) {
396 if (message === void 0) {
397 message = locale.required;
398 }
399
400 return this.test({
401 message: message,
402 name: 'required',
403 exclusive: true,
404 test: function test(value) {
405 return this.schema._isPresent(value);
406 }
407 });
408 },
409 notRequired: function notRequired() {
410 var next = this.clone();
411 next.tests = next.tests.filter(function (test) {
412 return test.OPTIONS.name !== 'required';
413 });
414 return next;
415 },
416 nullable: function nullable(isNullable) {
417 if (isNullable === void 0) {
418 isNullable = true;
419 }
420
421 var next = this.clone();
422 next._nullable = isNullable;
423 return next;
424 },
425 transform: function transform(fn) {
426 var next = this.clone();
427 next.transforms.push(fn);
428 return next;
429 },
430
431 /**
432 * Adds a test function to the schema's queue of tests.
433 * tests can be exclusive or non-exclusive.
434 *
435 * - exclusive tests, will replace any existing tests of the same name.
436 * - non-exclusive: can be stacked
437 *
438 * If a non-exclusive test is added to a schema with an exclusive test of the same name
439 * the exclusive test is removed and further tests of the same name will be stacked.
440 *
441 * If an exclusive test is added to a schema with non-exclusive tests of the same name
442 * the previous tests are removed and further tests of the same name will replace each other.
443 */
444 test: function test() {
445 var opts;
446
447 if (arguments.length === 1) {
448 if (typeof (arguments.length <= 0 ? undefined : arguments[0]) === 'function') {
449 opts = {
450 test: arguments.length <= 0 ? undefined : arguments[0]
451 };
452 } else {
453 opts = arguments.length <= 0 ? undefined : arguments[0];
454 }
455 } else if (arguments.length === 2) {
456 opts = {
457 name: arguments.length <= 0 ? undefined : arguments[0],
458 test: arguments.length <= 1 ? undefined : arguments[1]
459 };
460 } else {
461 opts = {
462 name: arguments.length <= 0 ? undefined : arguments[0],
463 message: arguments.length <= 1 ? undefined : arguments[1],
464 test: arguments.length <= 2 ? undefined : arguments[2]
465 };
466 }
467
468 if (opts.message === undefined) opts.message = locale.default;
469 if (typeof opts.test !== 'function') throw new TypeError('`test` is a required parameters');
470 var next = this.clone();
471 var validate = createValidation(opts);
472 var isExclusive = opts.exclusive || opts.name && next._exclusive[opts.name] === true;
473
474 if (opts.exclusive && !opts.name) {
475 throw new TypeError('Exclusive tests must provide a unique `name` identifying the test');
476 }
477
478 next._exclusive[opts.name] = !!opts.exclusive;
479 next.tests = next.tests.filter(function (fn) {
480 if (fn.OPTIONS.name === opts.name) {
481 if (isExclusive) return false;
482 if (fn.OPTIONS.test === validate.OPTIONS.test) return false;
483 }
484
485 return true;
486 });
487 next.tests.push(validate);
488 return next;
489 },
490 when: function when(keys, options) {
491 if (arguments.length === 1) {
492 options = keys;
493 keys = '.';
494 }
495
496 var next = this.clone(),
497 deps = [].concat(keys).map(function (key) {
498 return new Ref(key);
499 });
500 deps.forEach(function (dep) {
501 if (dep.isSibling) next._deps.push(dep.key);
502 });
503
504 next._conditions.push(new Condition(deps, options));
505
506 return next;
507 },
508 typeError: function typeError(message) {
509 var next = this.clone();
510 next._typeError = createValidation({
511 message: message,
512 name: 'typeError',
513 test: function test(value) {
514 if (value !== undefined && !this.schema.isType(value)) return this.createError({
515 params: {
516 type: this.schema._type
517 }
518 });
519 return true;
520 }
521 });
522 return next;
523 },
524 oneOf: function oneOf(enums, message) {
525 if (message === void 0) {
526 message = locale.oneOf;
527 }
528
529 var next = this.clone();
530 enums.forEach(function (val) {
531 next._whitelist.add(val);
532
533 next._blacklist.delete(val);
534 });
535 next._whitelistError = createValidation({
536 message: message,
537 name: 'oneOf',
538 test: function test(value) {
539 if (value === undefined) return true;
540 var valids = this.schema._whitelist;
541 return valids.has(value, this.resolve) ? true : this.createError({
542 params: {
543 values: valids.toArray().join(', ')
544 }
545 });
546 }
547 });
548 return next;
549 },
550 notOneOf: function notOneOf(enums, message) {
551 if (message === void 0) {
552 message = locale.notOneOf;
553 }
554
555 var next = this.clone();
556 enums.forEach(function (val) {
557 next._blacklist.add(val);
558
559 next._whitelist.delete(val);
560 });
561 next._blacklistError = createValidation({
562 message: message,
563 name: 'notOneOf',
564 test: function test(value) {
565 var invalids = this.schema._blacklist;
566 if (invalids.has(value, this.resolve)) return this.createError({
567 params: {
568 values: invalids.toArray().join(', ')
569 }
570 });
571 return true;
572 }
573 });
574 return next;
575 },
576 strip: function strip(_strip) {
577 if (_strip === void 0) {
578 _strip = true;
579 }
580
581 var next = this.clone();
582 next._strip = _strip;
583 return next;
584 },
585 _option: function _option(key, overrides) {
586 return has(overrides, key) ? overrides[key] : this._options[key];
587 },
588 describe: function describe() {
589 var next = this.clone();
590 var description = {
591 type: next._type,
592 meta: next._meta,
593 label: next._label,
594 tests: next.tests.map(function (fn) {
595 return {
596 name: fn.OPTIONS.name,
597 params: fn.OPTIONS.params
598 };
599 }).filter(function (n, idx, list) {
600 return list.findIndex(function (c) {
601 return c.name === n.name;
602 }) === idx;
603 })
604 };
605 if (next._whitelist.size) description.oneOf = next._whitelist.describe();
606 if (next._blacklist.size) description.notOneOf = next._blacklist.describe();
607 return description;
608 },
609 defined: function defined(message) {
610 if (message === void 0) {
611 message = locale.defined;
612 }
613
614 return this.test({
615 message: message,
616 name: 'defined',
617 exclusive: true,
618 test: function test(value) {
619 return value !== undefined;
620 }
621 });
622 }
623};
624
625var _loop = function _loop() {
626 var method = _arr[_i];
627
628 proto[method + "At"] = function (path, value, options) {
629 if (options === void 0) {
630 options = {};
631 }
632
633 var _getIn = getIn(this, path, value, options.context),
634 parent = _getIn.parent,
635 parentPath = _getIn.parentPath,
636 schema = _getIn.schema;
637
638 return schema[method](parent && parent[parentPath], _extends({}, options, {
639 parent: parent,
640 path: path
641 }));
642 };
643};
644
645for (var _i = 0, _arr = ['validate', 'validateSync']; _i < _arr.length; _i++) {
646 _loop();
647}
648
649for (var _i2 = 0, _arr2 = ['equals', 'is']; _i2 < _arr2.length; _i2++) {
650 var alias = _arr2[_i2];
651 proto[alias] = proto.oneOf;
652}
653
654for (var _i3 = 0, _arr3 = ['not', 'nope']; _i3 < _arr3.length; _i3++) {
655 var _alias = _arr3[_i3];
656 proto[_alias] = proto.notOneOf;
657}
658
659proto.optional = proto.notRequired;
\No newline at end of file