text: "use strict";
  
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  
  exports.__esModule = true;
  exports.default = SchemaType;
  
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  
  var _has = _interopRequireDefault(require("lodash/has"));
  
  var _cloneDeepWith = _interopRequireDefault(require("lodash/cloneDeepWith"));
  
  var _toArray2 = _interopRequireDefault(require("lodash/toArray"));
  
  var _locale = require("./locale");
  
  var _Condition = _interopRequireDefault(require("./Condition"));
  
  var _runValidations = _interopRequireDefault(require("./util/runValidations"));
  
  var _prependDeep = _interopRequireDefault(require("./util/prependDeep"));
  
  var _isSchema = _interopRequireDefault(require("./util/isSchema"));
  
  var _createValidation = _interopRequireDefault(require("./util/createValidation"));
  
  var _printValue = _interopRequireDefault(require("./util/printValue"));
  
  var _Reference = _interopRequireDefault(require("./Reference"));
  
  var _reach = require("./util/reach");
  
  var RefSet = /*#__PURE__*/function () {
    function RefSet() {
      this.list = new Set();
      this.refs = new Map();
    }
  
    var _proto = RefSet.prototype;
  
    _proto.toArray = function toArray() {
      return (0, _toArray2.default)(this.list).concat((0, _toArray2.default)(this.refs.values()));
    };
  
    _proto.add = function add(value) {
      _Reference.default.isRef(value) ? this.refs.set(value.key, value) : this.list.add(value);
    };
  
    _proto.delete = function _delete(value) {
      _Reference.default.isRef(value) ? this.refs.delete(value.key) : this.list.delete(value);
    };
  
    _proto.has = function has(value, resolve) {
      if (this.list.has(value)) return true;
      var item,
          values = this.refs.values();
  
      while (item = values.next(), !item.done) {
        if (resolve(item.value) === value) return true;
      }
  
      return false;
    };
  
    _proto.clone = function clone() {
      var next = new RefSet();
      next.list = new Set(this.list);
      next.refs = new Map(this.refs);
      return next;
    };
  
    _proto.merge = function merge(newItems, removeItems) {
      var next = this.clone();
      newItems.list.forEach(function (value) {
        return next.add(value);
      });
      newItems.refs.forEach(function (value) {
        return next.add(value);
      });
      removeItems.list.forEach(function (value) {
        return next.delete(value);
      });
      removeItems.refs.forEach(function (value) {
        return next.delete(value);
      });
      return next;
    };
  
    return RefSet;
  }();
  
  function SchemaType(options) {
    var _this = this;
  
    if (options === void 0) {
      options = {};
    }
  
    if (!(this instanceof SchemaType)) return new SchemaType();
    this._deps = [];
    this._conditions = [];
    this._options = {
      abortEarly: true,
      recursive: true
    };
    this._exclusive = Object.create(null);
    this._whitelist = new RefSet();
    this._blacklist = new RefSet();
    this.tests = [];
    this.transforms = [];
    this.withMutation(function () {
      _this.typeError(_locale.mixed.notType);
    });
    if ((0, _has.default)(options, 'default')) this._defaultDefault = options.default;
    this.type = options.type || 'mixed'; // TODO: remove
  
    this._type = options.type || 'mixed';
  }
  
  var proto = SchemaType.prototype = {
    __isYupSchema__: true,
    constructor: SchemaType,
    clone: function clone() {
      var _this2 = this;
  
      if (this._mutate) return this; // if the nested value is a schema we can skip cloning, since
      // they are already immutable
  
      return (0, _cloneDeepWith.default)(this, function (value) {
        if ((0, _isSchema.default)(value) && value !== _this2) return value;
      });
    },
    label: function label(_label) {
      var next = this.clone();
      next._label = _label;
      return next;
    },
    meta: function meta(obj) {
      if (arguments.length === 0) return this._meta;
      var next = this.clone();
      next._meta = (0, _extends2.default)(next._meta || {}, obj);
      return next;
    },
    withMutation: function withMutation(fn) {
      var before = this._mutate;
      this._mutate = true;
      var result = fn(this);
      this._mutate = before;
      return result;
    },
    concat: function concat(schema) {
      if (!schema || schema === this) return this;
      if (schema._type !== this._type && this._type !== 'mixed') throw new TypeError("You cannot `concat()` schema's of different types: " + this._type + " and " + schema._type);
      var next = (0, _prependDeep.default)(schema.clone(), this); // new undefined default is overridden by old non-undefined one, revert
  
      if ((0, _has.default)(schema, '_default')) next._default = schema._default;
      next.tests = this.tests;
      next._exclusive = this._exclusive; // manually merge the blacklist/whitelist (the other `schema` takes
      // precedence in case of conflicts)
  
      next._whitelist = this._whitelist.merge(schema._whitelist, schema._blacklist);
      next._blacklist = this._blacklist.merge(schema._blacklist, schema._whitelist); // manually add the new tests to ensure
      // the deduping logic is consistent
  
      next.withMutation(function (next) {
        schema.tests.forEach(function (fn) {
          next.test(fn.OPTIONS);
        });
      });
      return next;
    },
    isType: function isType(v) {
      if (this._nullable && v === null) return true;
      return !this._typeCheck || this._typeCheck(v);
    },
    resolve: function resolve(options) {
      var schema = this;
  
      if (schema._conditions.length) {
        var conditions = schema._conditions;
        schema = schema.clone();
        schema._conditions = [];
        schema = conditions.reduce(function (schema, condition) {
          return condition.resolve(schema, options);
        }, schema);
        schema = schema.resolve(options);
      }
  
      return schema;
    },
    cast: function cast(value, options) {
      if (options === void 0) {
        options = {};
      }
  
      var resolvedSchema = this.resolve((0, _extends2.default)({}, options, {
        value: value
      }));
  
      var result = resolvedSchema._cast(value, options);
  
      if (value !== undefined && options.assert !== false && resolvedSchema.isType(result) !== true) {
        var formattedValue = (0, _printValue.default)(value);
        var formattedResult = (0, _printValue.default)(result);
        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 : ''));
      }
  
      return result;
    },
    _cast: function _cast(rawValue) {
      var _this3 = this;
  
      var value = rawValue === undefined ? rawValue : this.transforms.reduce(function (value, fn) {
        return fn.call(_this3, value, rawValue);
      }, rawValue);
  
      if (value === undefined && (0, _has.default)(this, '_default')) {
        value = this.default();
      }
  
      return value;
    },
    _validate: function _validate(_value, options) {
      var _this4 = this;
  
      if (options === void 0) {
        options = {};
      }
  
      var value = _value;
      var originalValue = options.originalValue != null ? options.originalValue : _value;
  
      var isStrict = this._option('strict', options);
  
      var endEarly = this._option('abortEarly', options);
  
      var sync = options.sync;
      var path = options.path;
      var label = this._label;
  
      if (!isStrict) {
        value = this._cast(value, (0, _extends2.default)({
          assert: false
        }, options));
      } // value is cast, we can check if it meets type requirements
  
  
      var validationParams = {
        value: value,
        path: path,
        schema: this,
        options: options,
        label: label,
        originalValue: originalValue,
        sync: sync
      };
      var initialTests = [];
      if (this._typeError) initialTests.push(this._typeError(validationParams));
      if (this._whitelistError) initialTests.push(this._whitelistError(validationParams));
      if (this._blacklistError) initialTests.push(this._blacklistError(validationParams));
      return (0, _runValidations.default)({
        validations: initialTests,
        endEarly: endEarly,
        value: value,
        path: path,
        sync: sync
      }).then(function (value) {
        return (0, _runValidations.default)({
          path: path,
          sync: sync,
          value: value,
          endEarly: endEarly,
          validations: _this4.tests.map(function (fn) {
            return fn(validationParams);
          })
        });
      });
    },
    validate: function validate(value, options) {
      if (options === void 0) {
        options = {};
      }
  
      var schema = this.resolve((0, _extends2.default)({}, options, {
        value: value
      }));
      return schema._validate(value, options);
    },
    validateSync: function validateSync(value, options) {
      if (options === void 0) {
        options = {};
      }
  
      var schema = this.resolve((0, _extends2.default)({}, options, {
        value: value
      }));
      var result, err;
  
      schema._validate(value, (0, _extends2.default)({}, options, {
        sync: true
      })).then(function (r) {
        return result = r;
      }).catch(function (e) {
        return err = e;
      });
  
      if (err) throw err;
      return result;
    },
    isValid: function isValid(value, options) {
      return this.validate(value, options).then(function () {
        return true;
      }).catch(function (err) {
        if (err.name === 'ValidationError') return false;
        throw err;
      });
    },
    isValidSync: function isValidSync(value, options) {
      try {
        this.validateSync(value, options);
        return true;
      } catch (err) {
        if (err.name === 'ValidationError') return false;
        throw err;
      }
    },
    getDefault: function getDefault(options) {
      if (options === void 0) {
        options = {};
      }
  
      var schema = this.resolve(options);
      return schema.default();
    },
    default: function _default(def) {
      if (arguments.length === 0) {
        var defaultValue = (0, _has.default)(this, '_default') ? this._default : this._defaultDefault;
        return typeof defaultValue === 'function' ? defaultValue.call(this) : (0, _cloneDeepWith.default)(defaultValue);
      }
  
      var next = this.clone();
      next._default = def;
      return next;
    },
    strict: function strict(isStrict) {
      if (isStrict === void 0) {
        isStrict = true;
      }
  
      var next = this.clone();
      next._options.strict = isStrict;
      return next;
    },
    _isPresent: function _isPresent(value) {
      return value != null;
    },
    required: function required(message) {
      if (message === void 0) {
        message = _locale.mixed.required;
      }
  
      return this.test({
        message: message,
        name: 'required',
        exclusive: true,
        test: function test(value) {
          return this.schema._isPresent(value);
        }
      });
    },
    notRequired: function notRequired() {
      var next = this.clone();
      next.tests = next.tests.filter(function (test) {
        return test.OPTIONS.name !== 'required';
      });
      return next;
    },
    nullable: function nullable(isNullable) {
      if (isNullable === void 0) {
        isNullable = true;
      }
  
      var next = this.clone();
      next._nullable = isNullable;
      return next;
    },
    transform: function transform(fn) {
      var next = this.clone();
      next.transforms.push(fn);
      return next;
    },
  
    /**
     * Adds a test function to the schema's queue of tests.
     * tests can be exclusive or non-exclusive.
     *
     * - exclusive tests, will replace any existing tests of the same name.
     * - non-exclusive: can be stacked
     *
     * If a non-exclusive test is added to a schema with an exclusive test of the same name
     * the exclusive test is removed and further tests of the same name will be stacked.
     *
     * If an exclusive test is added to a schema with non-exclusive tests of the same name
     * the previous tests are removed and further tests of the same name will replace each other.
     */
    test: function test() {
      var opts;
  
      if (arguments.length === 1) {
        if (typeof (arguments.length <= 0 ? undefined : arguments[0]) === 'function') {
          opts = {
            test: arguments.length <= 0 ? undefined : arguments[0]
          };
        } else {
          opts = arguments.length <= 0 ? undefined : arguments[0];
        }
      } else if (arguments.length === 2) {
        opts = {
          name: arguments.length <= 0 ? undefined : arguments[0],
          test: arguments.length <= 1 ? undefined : arguments[1]
        };
      } else {
        opts = {
          name: arguments.length <= 0 ? undefined : arguments[0],
          message: arguments.length <= 1 ? undefined : arguments[1],
          test: arguments.length <= 2 ? undefined : arguments[2]
        };
      }
  
      if (opts.message === undefined) opts.message = _locale.mixed.default;
      if (typeof opts.test !== 'function') throw new TypeError('`test` is a required parameters');
      var next = this.clone();
      var validate = (0, _createValidation.default)(opts);
      var isExclusive = opts.exclusive || opts.name && next._exclusive[opts.name] === true;
  
      if (opts.exclusive && !opts.name) {
        throw new TypeError('Exclusive tests must provide a unique `name` identifying the test');
      }
  
      next._exclusive[opts.name] = !!opts.exclusive;
      next.tests = next.tests.filter(function (fn) {
        if (fn.OPTIONS.name === opts.name) {
          if (isExclusive) return false;
          if (fn.OPTIONS.test === validate.OPTIONS.test) return false;
        }
  
        return true;
      });
      next.tests.push(validate);
      return next;
    },
    when: function when(keys, options) {
      if (arguments.length === 1) {
        options = keys;
        keys = '.';
      }
  
      var next = this.clone(),
          deps = [].concat(keys).map(function (key) {
        return new _Reference.default(key);
      });
      deps.forEach(function (dep) {
        if (dep.isSibling) next._deps.push(dep.key);
      });
  
      next._conditions.push(new _Condition.default(deps, options));
  
      return next;
    },
    typeError: function typeError(message) {
      var next = this.clone();
      next._typeError = (0, _createValidation.default)({
        message: message,
        name: 'typeError',
        test: function test(value) {
          if (value !== undefined && !this.schema.isType(value)) return this.createError({
            params: {
              type: this.schema._type
            }
          });
          return true;
        }
      });
      return next;
    },
    oneOf: function oneOf(enums, message) {
      if (message === void 0) {
        message = _locale.mixed.oneOf;
      }
  
      var next = this.clone();
      enums.forEach(function (val) {
        next._whitelist.add(val);
  
        next._blacklist.delete(val);
      });
      next._whitelistError = (0, _createValidation.default)({
        message: message,
        name: 'oneOf',
        test: function test(value) {
          if (value === undefined) return true;
          var valids = this.schema._whitelist;
          return valids.has(value, this.resolve) ? true : this.createError({
            params: {
              values: valids.toArray().join(', ')
            }
          });
        }
      });
      return next;
    },
    notOneOf: function notOneOf(enums, message) {
      if (message === void 0) {
        message = _locale.mixed.notOneOf;
      }
  
      var next = this.clone();
      enums.forEach(function (val) {
        next._blacklist.add(val);
  
        next._whitelist.delete(val);
      });
      next._blacklistError = (0, _createValidation.default)({
        message: message,
        name: 'notOneOf',
        test: function test(value) {
          var invalids = this.schema._blacklist;
          if (invalids.has(value, this.resolve)) return this.createError({
            params: {
              values: invalids.toArray().join(', ')
            }
          });
          return true;
        }
      });
      return next;
    },
    strip: function strip(_strip) {
      if (_strip === void 0) {
        _strip = true;
      }
  
      var next = this.clone();
      next._strip = _strip;
      return next;
    },
    _option: function _option(key, overrides) {
      return (0, _has.default)(overrides, key) ? overrides[key] : this._options[key];
    },
    describe: function describe() {
      var next = this.clone();
      return {
        type: next._type,
        meta: next._meta,
        label: next._label,
        tests: next.tests.map(function (fn) {
          return {
            name: fn.OPTIONS.name,
            params: fn.OPTIONS.params
          };
        }).filter(function (n, idx, list) {
          return list.findIndex(function (c) {
            return c.name === n.name;
          }) === idx;
        })
      };
    },
    defined: function defined(message) {
      if (message === void 0) {
        message = _locale.mixed.defined;
      }
  
      return this.nullable().test({
        message: message,
        name: 'defined',
        exclusive: true,
        test: function test(value) {
          return value !== undefined;
        }
      });
    }
  };
  
  var _loop = function _loop() {
    var method = _arr[_i];
  
    proto[method + "At"] = function (path, value, options) {
      if (options === void 0) {
        options = {};
      }
  
      var _getIn = (0, _reach.getIn)(this, path, value, options.context),
          parent = _getIn.parent,
          parentPath = _getIn.parentPath,
          schema = _getIn.schema;
  
      return schema[method](parent && parent[parentPath], (0, _extends2.default)({}, options, {
        parent: parent,
        path: path
      }));
    };
  };
  
  for (var _i = 0, _arr = ['validate', 'validateSync']; _i < _arr.length; _i++) {
    _loop();
  }
  
  for (var _i2 = 0, _arr2 = ['equals', 'is']; _i2 < _arr2.length; _i2++) {
    var alias = _arr2[_i2];
    proto[alias] = proto.oneOf;
  }
  
  for (var _i3 = 0, _arr3 = ['not', 'nope']; _i3 < _arr3.length; _i3++) {
    var _alias = _arr3[_i3];
    proto[_alias] = proto.notOneOf;
  }
  
  proto.optional = proto.notRequired;
  module.exports = exports.default;