rittenhop-dev/versions/5.94.2/node_modules/yup/es/schema.js

560 lines
14 KiB
JavaScript
Raw Normal View History

2024-09-23 19:40:12 -04:00
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
// @ts-ignore
import cloneDeep from 'nanoclone';
import { mixed as locale } from './locale';
import Condition from './Condition';
import runTests from './util/runTests';
import createValidation from './util/createValidation';
import printValue from './util/printValue';
import Ref from './Reference';
import { getIn } from './util/reach';
import toArray from './util/toArray';
import ValidationError from './ValidationError';
import ReferenceSet from './util/ReferenceSet';
export default class BaseSchema {
constructor(options) {
this.deps = [];
this.conditions = [];
this._whitelist = new ReferenceSet();
this._blacklist = new ReferenceSet();
this.exclusiveTests = Object.create(null);
this.tests = [];
this.transforms = [];
this.withMutation(() => {
this.typeError(locale.notType);
});
this.type = (options == null ? void 0 : options.type) || 'mixed';
this.spec = _extends({
strip: false,
strict: false,
abortEarly: true,
recursive: true,
nullable: false,
presence: 'optional'
}, options == null ? void 0 : options.spec);
} // TODO: remove
get _type() {
return this.type;
}
_typeCheck(_value) {
return true;
}
clone(spec) {
if (this._mutate) {
if (spec) Object.assign(this.spec, spec);
return this;
} // if the nested value is a schema we can skip cloning, since
// they are already immutable
const next = Object.create(Object.getPrototypeOf(this)); // @ts-expect-error this is readonly
next.type = this.type;
next._typeError = this._typeError;
next._whitelistError = this._whitelistError;
next._blacklistError = this._blacklistError;
next._whitelist = this._whitelist.clone();
next._blacklist = this._blacklist.clone();
next.exclusiveTests = _extends({}, this.exclusiveTests); // @ts-expect-error this is readonly
next.deps = [...this.deps];
next.conditions = [...this.conditions];
next.tests = [...this.tests];
next.transforms = [...this.transforms];
next.spec = cloneDeep(_extends({}, this.spec, spec));
return next;
}
label(label) {
var next = this.clone();
next.spec.label = label;
return next;
}
meta(...args) {
if (args.length === 0) return this.spec.meta;
let next = this.clone();
next.spec.meta = Object.assign(next.spec.meta || {}, args[0]);
return next;
} // withContext<TContext extends AnyObject>(): BaseSchema<
// TCast,
// TContext,
// TOutput
// > {
// return this as any;
// }
withMutation(fn) {
let before = this._mutate;
this._mutate = true;
let result = fn(this);
this._mutate = before;
return result;
}
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}`);
let base = this;
let combined = schema.clone();
const mergedSpec = _extends({}, base.spec, combined.spec); // if (combined.spec.nullable === UNSET)
// mergedSpec.nullable = base.spec.nullable;
// if (combined.spec.presence === UNSET)
// mergedSpec.presence = base.spec.presence;
combined.spec = mergedSpec;
combined._typeError || (combined._typeError = base._typeError);
combined._whitelistError || (combined._whitelistError = base._whitelistError);
combined._blacklistError || (combined._blacklistError = base._blacklistError); // manually merge the blacklist/whitelist (the other `schema` takes
// precedence in case of conflicts)
combined._whitelist = base._whitelist.merge(schema._whitelist, schema._blacklist);
combined._blacklist = base._blacklist.merge(schema._blacklist, schema._whitelist); // start with the current tests
combined.tests = base.tests;
combined.exclusiveTests = base.exclusiveTests; // manually add the new tests to ensure
// the deduping logic is consistent
combined.withMutation(next => {
schema.tests.forEach(fn => {
next.test(fn.OPTIONS);
});
});
return combined;
}
isType(v) {
if (this.spec.nullable && v === null) return true;
return this._typeCheck(v);
}
resolve(options) {
let schema = this;
if (schema.conditions.length) {
let conditions = schema.conditions;
schema = schema.clone();
schema.conditions = [];
schema = conditions.reduce((schema, condition) => condition.resolve(schema, options), schema);
schema = schema.resolve(options);
}
return schema;
}
/**
*
* @param {*} value
* @param {Object} options
* @param {*=} options.parent
* @param {*=} options.context
*/
cast(value, options = {}) {
let resolvedSchema = this.resolve(_extends({
value
}, options));
let result = resolvedSchema._cast(value, options);
if (value !== undefined && options.assert !== false && resolvedSchema.isType(result) !== true) {
let formattedValue = printValue(value);
let formattedResult = printValue(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(rawValue, _options) {
let value = rawValue === undefined ? rawValue : this.transforms.reduce((value, fn) => fn.call(this, value, rawValue, this), rawValue);
if (value === undefined) {
value = this.getDefault();
}
return value;
}
_validate(_value, options = {}, cb) {
let {
sync,
path,
from = [],
originalValue = _value,
strict = this.spec.strict,
abortEarly = this.spec.abortEarly
} = options;
let value = _value;
if (!strict) {
// this._validating = true;
value = this._cast(value, _extends({
assert: false
}, options)); // this._validating = false;
} // value is cast, we can check if it meets type requirements
let args = {
value,
path,
options,
originalValue,
schema: this,
label: this.spec.label,
sync,
from
};
let initialTests = [];
if (this._typeError) initialTests.push(this._typeError);
if (this._whitelistError) initialTests.push(this._whitelistError);
if (this._blacklistError) initialTests.push(this._blacklistError);
runTests({
args,
value,
path,
sync,
tests: initialTests,
endEarly: abortEarly
}, err => {
if (err) return void cb(err, value);
runTests({
tests: this.tests,
args,
path,
sync,
value,
endEarly: abortEarly
}, cb);
});
}
validate(value, options, maybeCb) {
let schema = this.resolve(_extends({}, options, {
value
})); // callback case is for nested validations
return typeof maybeCb === 'function' ? schema._validate(value, options, maybeCb) : new Promise((resolve, reject) => schema._validate(value, options, (err, value) => {
if (err) reject(err);else resolve(value);
}));
}
validateSync(value, options) {
let schema = this.resolve(_extends({}, options, {
value
}));
let result;
schema._validate(value, _extends({}, options, {
sync: true
}), (err, value) => {
if (err) throw err;
result = value;
});
return result;
}
isValid(value, options) {
return this.validate(value, options).then(() => true, err => {
if (ValidationError.isError(err)) return false;
throw err;
});
}
isValidSync(value, options) {
try {
this.validateSync(value, options);
return true;
} catch (err) {
if (ValidationError.isError(err)) return false;
throw err;
}
}
_getDefault() {
let defaultValue = this.spec.default;
if (defaultValue == null) {
return defaultValue;
}
return typeof defaultValue === 'function' ? defaultValue.call(this) : cloneDeep(defaultValue);
}
getDefault(options) {
let schema = this.resolve(options || {});
return schema._getDefault();
}
default(def) {
if (arguments.length === 0) {
return this._getDefault();
}
let next = this.clone({
default: def
});
return next;
}
strict(isStrict = true) {
var next = this.clone();
next.spec.strict = isStrict;
return next;
}
_isPresent(value) {
return value != null;
}
defined(message = locale.defined) {
return this.test({
message,
name: 'defined',
exclusive: true,
test(value) {
return value !== undefined;
}
});
}
required(message = locale.required) {
return this.clone({
presence: 'required'
}).withMutation(s => s.test({
message,
name: 'required',
exclusive: true,
test(value) {
return this.schema._isPresent(value);
}
}));
}
notRequired() {
var next = this.clone({
presence: 'optional'
});
next.tests = next.tests.filter(test => test.OPTIONS.name !== 'required');
return next;
}
nullable(isNullable = true) {
var next = this.clone({
nullable: isNullable !== false
});
return next;
}
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(...args) {
let opts;
if (args.length === 1) {
if (typeof args[0] === 'function') {
opts = {
test: args[0]
};
} else {
opts = args[0];
}
} else if (args.length === 2) {
opts = {
name: args[0],
test: args[1]
};
} else {
opts = {
name: args[0],
message: args[1],
test: args[2]
};
}
if (opts.message === undefined) opts.message = locale.default;
if (typeof opts.test !== 'function') throw new TypeError('`test` is a required parameters');
let next = this.clone();
let validate = createValidation(opts);
let isExclusive = opts.exclusive || opts.name && next.exclusiveTests[opts.name] === true;
if (opts.exclusive) {
if (!opts.name) throw new TypeError('Exclusive tests must provide a unique `name` identifying the test');
}
if (opts.name) next.exclusiveTests[opts.name] = !!opts.exclusive;
next.tests = next.tests.filter(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(keys, options) {
if (!Array.isArray(keys) && typeof keys !== 'string') {
options = keys;
keys = '.';
}
let next = this.clone();
let deps = toArray(keys).map(key => new Ref(key));
deps.forEach(dep => {
// @ts-ignore
if (dep.isSibling) next.deps.push(dep.key);
});
next.conditions.push(new Condition(deps, options));
return next;
}
typeError(message) {
var next = this.clone();
next._typeError = createValidation({
message,
name: 'typeError',
test(value) {
if (value !== undefined && !this.schema.isType(value)) return this.createError({
params: {
type: this.schema._type
}
});
return true;
}
});
return next;
}
oneOf(enums, message = locale.oneOf) {
var next = this.clone();
enums.forEach(val => {
next._whitelist.add(val);
next._blacklist.delete(val);
});
next._whitelistError = createValidation({
message,
name: 'oneOf',
test(value) {
if (value === undefined) return true;
let valids = this.schema._whitelist;
return valids.has(value, this.resolve) ? true : this.createError({
params: {
values: valids.toArray().join(', ')
}
});
}
});
return next;
}
notOneOf(enums, message = locale.notOneOf) {
var next = this.clone();
enums.forEach(val => {
next._blacklist.add(val);
next._whitelist.delete(val);
});
next._blacklistError = createValidation({
message,
name: 'notOneOf',
test(value) {
let invalids = this.schema._blacklist;
if (invalids.has(value, this.resolve)) return this.createError({
params: {
values: invalids.toArray().join(', ')
}
});
return true;
}
});
return next;
}
strip(strip = true) {
let next = this.clone();
next.spec.strip = strip;
return next;
}
describe() {
const next = this.clone();
const {
label,
meta
} = next.spec;
const description = {
meta,
label,
type: next.type,
oneOf: next._whitelist.describe(),
notOneOf: next._blacklist.describe(),
tests: next.tests.map(fn => ({
name: fn.OPTIONS.name,
params: fn.OPTIONS.params
})).filter((n, idx, list) => list.findIndex(c => c.name === n.name) === idx)
};
return description;
}
}
// @ts-expect-error
BaseSchema.prototype.__isYupSchema__ = true;
for (const method of ['validate', 'validateSync']) BaseSchema.prototype[`${method}At`] = function (path, value, options = {}) {
const {
parent,
parentPath,
schema
} = getIn(this, path, value, options.context);
return schema[method](parent && parent[parentPath], _extends({}, options, {
parent,
path
}));
};
for (const alias of ['equals', 'is']) BaseSchema.prototype[alias] = BaseSchema.prototype.oneOf;
for (const alias of ['not', 'nope']) BaseSchema.prototype[alias] = BaseSchema.prototype.notOneOf;
BaseSchema.prototype.optional = BaseSchema.prototype.notRequired;