559 lines
15 KiB
JavaScript
559 lines
15 KiB
JavaScript
"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 _merge = _interopRequireDefault(require("./util/merge"));
|
|
|
|
var _isSchema = _interopRequireDefault(require("./util/isSchema"));
|
|
|
|
var _isAbsent = _interopRequireDefault(require("./util/isAbsent"));
|
|
|
|
var _createValidation = _interopRequireDefault(require("./util/createValidation"));
|
|
|
|
var _printValue = _interopRequireDefault(require("./util/printValue"));
|
|
|
|
var _Reference = _interopRequireDefault(require("./Reference"));
|
|
|
|
var _reach = require("./util/reach");
|
|
|
|
var notEmpty = function notEmpty(value) {
|
|
return !(0, _isAbsent.default)(value);
|
|
};
|
|
|
|
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, value) : 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;
|
|
};
|
|
|
|
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';
|
|
}
|
|
|
|
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) {
|
|
this._mutate = true;
|
|
var result = fn(this);
|
|
this._mutate = false;
|
|
return result;
|
|
},
|
|
concat: function concat(schema) {
|
|
if (!schema) 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 cloned = this.clone();
|
|
var next = (0, _merge.default)(this.clone(), schema.clone()); // undefined isn't merged over, but is a valid value for default
|
|
|
|
if ((0, _has.default)(schema, '_default')) next._default = schema._default;
|
|
next.tests = cloned.tests;
|
|
next._exclusive = cloned._exclusive; // manually add the new tests to ensure
|
|
// the deduping logic is consistent
|
|
|
|
schema.tests.forEach(function (fn) {
|
|
next = next.test(fn.OPTIONS);
|
|
});
|
|
next._type = schema._type;
|
|
return next;
|
|
},
|
|
isType: function isType(v) {
|
|
if (this._nullable && v === null) return true;
|
|
return !this._typeCheck || this._typeCheck(v);
|
|
},
|
|
resolve: function resolve(_ref) {
|
|
var context = _ref.context,
|
|
parent = _ref.parent;
|
|
|
|
if (this._conditions.length) {
|
|
return this._conditions.reduce(function (schema, match) {
|
|
return match.resolve(schema, match.getValue(parent, context));
|
|
}, this);
|
|
}
|
|
|
|
return this;
|
|
},
|
|
cast: function cast(value, options) {
|
|
if (options === void 0) {
|
|
options = {};
|
|
}
|
|
|
|
var resolvedSchema = this.resolve(options);
|
|
|
|
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(options);
|
|
return schema._validate(value, options);
|
|
},
|
|
validateSync: function validateSync(value, options) {
|
|
if (options === void 0) {
|
|
options = {};
|
|
}
|
|
|
|
var schema = this.resolve(options);
|
|
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, (0, _extends2.default)({}, 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() {
|
|
var next = this.clone();
|
|
next._options.strict = true;
|
|
return next;
|
|
},
|
|
required: function required(message) {
|
|
if (message === void 0) {
|
|
message = _locale.mixed.required;
|
|
}
|
|
|
|
return this.test({
|
|
message: message,
|
|
name: 'required',
|
|
test: notEmpty
|
|
});
|
|
},
|
|
notRequired: function notRequired() {
|
|
var next = this.clone();
|
|
next.tests = next.tests.filter(function (test) {
|
|
return test.OPTIONS.name !== 'required';
|
|
});
|
|
return next;
|
|
},
|
|
nullable: function nullable(value) {
|
|
var next = this.clone();
|
|
next._nullable = value === false ? false : true;
|
|
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() {
|
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
var opts = args[0];
|
|
|
|
if (args.length > 1) {
|
|
var name = args[0],
|
|
message = args[1],
|
|
test = args[2];
|
|
|
|
if (test == null) {
|
|
test = message;
|
|
message = _locale.mixed.default;
|
|
}
|
|
|
|
opts = {
|
|
name: name,
|
|
test: test,
|
|
message: message,
|
|
exclusive: false
|
|
};
|
|
}
|
|
|
|
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) {
|
|
var next = this.clone(),
|
|
deps = [].concat(keys).map(function (key) {
|
|
return new _Reference.default(key);
|
|
});
|
|
deps.forEach(function (dep) {
|
|
if (!dep.isContext) 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;
|
|
})
|
|
};
|
|
}
|
|
};
|
|
var _arr = ['validate', 'validateSync'];
|
|
|
|
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; _i < _arr.length; _i++) {
|
|
_loop();
|
|
}
|
|
|
|
var _arr2 = ['equals', 'is'];
|
|
|
|
for (var _i2 = 0; _i2 < _arr2.length; _i2++) {
|
|
var alias = _arr2[_i2];
|
|
proto[alias] = proto.oneOf;
|
|
}
|
|
|
|
var _arr3 = ['not', 'nope'];
|
|
|
|
for (var _i3 = 0; _i3 < _arr3.length; _i3++) {
|
|
var _alias = _arr3[_i3];
|
|
proto[_alias] = proto.notOneOf;
|
|
}
|
|
|
|
module.exports = exports["default"]; |