Comparing version 4.3.0 to 5.0.0-alpha.1
2301
esm/index.js
@@ -1,1393 +0,1631 @@ | ||
function isObject(value) { | ||
return !!value && typeof value === 'object' && !Array.isArray(value); | ||
} | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _extends() { | ||
_extends = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
// Bundled with Packemon: https://packemon.dev | ||
// Platform: browser, Support: stable, Format: esm | ||
class ValidationError extends Error { | ||
constructor(message, path = '', value = undefined) { | ||
super(message); | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
_defineProperty(this, "errors", []); | ||
_defineProperty(this, "path", void 0); | ||
_defineProperty(this, "value", void 0); | ||
this.name = 'ValidationError'; | ||
this.path = path; | ||
this.value = value; | ||
if (path) { | ||
const key = pathKey(path); | ||
this.message = `${key.includes('[') ? `Invalid member "${key}".` : `Invalid field "${key}".`} ${this.message}`; | ||
} | ||
} | ||
return target; | ||
}; | ||
addError(error) { | ||
const validError = error instanceof ValidationError ? error : new ValidationError(error.message); | ||
const hasSameError = this.errors.some(e => e.message === error.message); | ||
return _extends.apply(this, arguments); | ||
if (hasSameError) { | ||
return; | ||
} | ||
this.errors.push(validError); | ||
this.message += '\n'; | ||
this.message += error.message.split('\n').map(line => line.match(/^\s+-/) ? ` ${line}` : ` - ${line}`).join('\n'); | ||
} | ||
} | ||
function _inheritsLoose(subClass, superClass) { | ||
subClass.prototype = Object.create(superClass.prototype); | ||
subClass.prototype.constructor = subClass; | ||
function isObject(value) { | ||
return !!value && typeof value === 'object' && !Array.isArray(value); | ||
} | ||
_setPrototypeOf(subClass, superClass); | ||
function isSchema(value) { | ||
return isObject(value) && typeof value.schema === 'function' && typeof value.type === 'function' && typeof value.validate === 'function'; | ||
} | ||
function _setPrototypeOf(o, p) { | ||
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { | ||
o.__proto__ = p; | ||
return o; | ||
}; | ||
function isValidDate(value) { | ||
return Object.prototype.toString.call(value) === '[object Date]' && !Number.isNaN(value.getTime()) && value.toString() !== 'Invalid Date'; | ||
} | ||
return _setPrototypeOf(o, p); | ||
function isValidNumber(value) { | ||
return typeof value === 'number' && !Number.isNaN(value); | ||
} | ||
function logUnknown(unknownFields, pathPrefix) { | ||
var unknownKeys = Object.keys(unknownFields); | ||
function isValidString(value) { | ||
return typeof value === 'string' && value !== ''; | ||
} | ||
if (unknownKeys.length > 0) { | ||
var message = pathPrefix ? "Unknown \"" + pathPrefix + "\" fields" : 'Unknown fields'; | ||
throw new Error(message + ": " + unknownKeys.join(', ') + "."); | ||
function createArray(value) { | ||
if (value === undefined) { | ||
return []; | ||
} | ||
return Array.isArray(value) ? [...value] : [value]; | ||
} | ||
function typeOf(value) { | ||
if (Array.isArray(value)) { | ||
return 'array'; | ||
function createDate(value) { | ||
if (value instanceof Date) { | ||
return value; | ||
} | ||
if (isObject(value)) { | ||
return value.constructor.name === 'Object' ? 'object' : 'instance'; | ||
if (value === undefined || value === null) { | ||
return new Date(); | ||
} | ||
switch (typeof value) { | ||
case 'boolean': | ||
case 'function': | ||
case 'number': | ||
case 'string': | ||
return typeof value; | ||
return new Date(value); | ||
} | ||
default: | ||
return 'unknown'; | ||
} | ||
function createObject(value) { | ||
return isObject(value) ? { ...value | ||
} : {}; | ||
} | ||
/** | ||
* Native `instanceof` checks are problematic, as cross realm checks fail. | ||
* They will also fail when comparing against source and compiled files. | ||
* So emulate an `instanceof` check by comparing constructor names. | ||
*/ | ||
var Predicate = function () { | ||
function Predicate(type, defaultValue, bypassFactory) { | ||
if (bypassFactory === void 0) { | ||
bypassFactory = false; | ||
} | ||
this.defaultValue = void 0; | ||
this.schema = void 0; | ||
this.type = void 0; | ||
this.checks = []; | ||
this.defaultValueFactory = void 0; | ||
this.deprecatedMessage = ''; | ||
this.errorMessage = ''; | ||
this.isNever = false; | ||
this.isNullable = false; | ||
this.isRequired = false; | ||
this.noErrorPrefix = false; | ||
function instanceOf(object, contract) { | ||
if (!object || typeof object !== 'object') { | ||
return false; | ||
} | ||
if (typeof defaultValue === 'function' && !bypassFactory) { | ||
this.defaultValueFactory = defaultValue; | ||
} else { | ||
this.defaultValue = defaultValue; | ||
if (object instanceof contract) { | ||
return true; | ||
} | ||
let current = object; | ||
while (current) { | ||
if (current.constructor.name === 'Object') { | ||
return false; | ||
} | ||
this.type = type; | ||
if (current.constructor.name === contract.name || current instanceof Error && current.name === contract.name) { | ||
return true; | ||
} // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
current = Object.getPrototypeOf(current); | ||
} | ||
var _proto = Predicate.prototype; | ||
return false; | ||
} | ||
_proto.and = function and() { | ||
var _this = this; | ||
function invalid(condition, message, path = '', value = undefined) { | ||
if (condition) { | ||
return; | ||
} | ||
for (var _len = arguments.length, keys = new Array(_len), _key = 0; _key < _len; _key++) { | ||
keys[_key] = arguments[_key]; | ||
} | ||
throw new ValidationError(message, path, value); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(keys.length > 0, 'AND requires a list of field names.'); | ||
this.addCheck(function (path) { | ||
var _this$schema$parentSt, _this$schema; | ||
function invariant(condition, message) { | ||
if (condition) { | ||
return; | ||
} | ||
var andKeys = [_this.key(path)].concat(keys); | ||
var struct = (_this$schema$parentSt = (_this$schema = _this.schema) == null ? void 0 : _this$schema.parentStruct) != null ? _this$schema$parentSt : {}; | ||
var undefs = andKeys.filter(function (key) { | ||
return struct[key] === undefined || struct[key] === null; | ||
}); | ||
throw new Error(message); | ||
} | ||
if (undefs.length === andKeys.length) { | ||
return; | ||
} | ||
function logUnknown(unknownFields, pathPrefix) { | ||
const unknownKeys = Object.keys(unknownFields); | ||
_this.invariant(undefs.length === 0, "All of these fields must be defined: " + andKeys.join(', ')); | ||
}); | ||
} | ||
if (unknownKeys.length > 0) { | ||
throw new Error(`${pathPrefix ? `Unknown "${pathPrefix}" fields` : 'Unknown fields'}: ${unknownKeys.join(', ')}.`); | ||
} | ||
} | ||
return this; | ||
}; | ||
function pathKey(path) { | ||
if (path.endsWith(']')) { | ||
const index = path.lastIndexOf('['); | ||
return index > 0 ? path.slice(index) : path; | ||
} | ||
_proto.cast = function cast(value) { | ||
return value; | ||
}; | ||
const index = path.lastIndexOf('.'); | ||
return index > 0 ? path.slice(index + 1) : path; | ||
} | ||
_proto.custom = function custom(callback) { | ||
var _this2 = this; | ||
function tryAndCollect(validator, validError, collectErrors) { | ||
let result = false; | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(typeof callback === 'function', 'Custom blueprints require a validation function.'); | ||
this.addCheck(function (path, value) { | ||
try { | ||
callback(value, _this2.schema); | ||
} catch (error) { | ||
_this2.invariant(false, error.message, path); | ||
} | ||
}); | ||
try { | ||
const value = validator(); | ||
if (typeof value === 'boolean') { | ||
result = value; | ||
} | ||
} catch (error) { | ||
if (error instanceof Error && collectErrors) { | ||
validError.addError(error); | ||
} else { | ||
throw error; | ||
} | ||
} | ||
return this; | ||
}; | ||
return result; | ||
} | ||
_proto.default = function _default() { | ||
var _this$schema$struct, _this$schema2; | ||
class OptimalError extends ValidationError { | ||
constructor() { | ||
super(''); | ||
var value = this.defaultValueFactory ? this.defaultValueFactory((_this$schema$struct = (_this$schema2 = this.schema) == null ? void 0 : _this$schema2.struct) != null ? _this$schema$struct : {}) : this.defaultValue; | ||
_defineProperty(this, "file", ''); | ||
if (value === null) { | ||
return null; | ||
} | ||
_defineProperty(this, "schema", ''); | ||
return this.cast(value); | ||
}; | ||
this.name = 'OptimalError'; | ||
} | ||
_proto.deprecate = function deprecate(message) { | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(typeof message === 'string' && !!message, 'A non-empty string is required for deprecated messages.'); | ||
} | ||
addError(error) { | ||
const validError = error instanceof ValidationError ? error : new ValidationError(error.message); | ||
this.errors.push(validError); // Avoid indenting at this level | ||
this.deprecatedMessage = message; | ||
return this; | ||
}; | ||
this.message = `${this.message}\n${error.message}`.trim(); | ||
} | ||
_proto.invariant = function invariant(condition, message, path) { | ||
if (path === void 0) { | ||
path = ''; | ||
} | ||
/** | ||
* Run all validation checks that have been enqueued and return a type casted value. | ||
* If a value is undefined, inherit the default value, else throw if required. | ||
* If nullable and the value is null, return early. | ||
*/ | ||
function validate(state, validators, initialValue, path = '', { | ||
collectErrors = true, | ||
currentObject = {}, | ||
rootObject = currentObject | ||
} = {}) { | ||
const { | ||
defaultValue, | ||
metadata | ||
} = state; | ||
let value = initialValue; // Handle undefined | ||
if (value === undefined) { | ||
value = typeof defaultValue === 'function' ? defaultValue(path, currentObject, rootObject) : defaultValue; | ||
invalid(!state.required, 'Field is required and must be defined.', path); | ||
} else { | ||
if (process.env.NODE_ENV !== "production" && metadata.deprecatedMessage) { | ||
// eslint-disable-next-line no-console | ||
console.info(`Field "${path}" is deprecated. ${metadata.deprecatedMessage}`); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
if (condition) { | ||
return; | ||
} | ||
invalid(!state.never, 'Field should never be used.', path); | ||
} // Handle null | ||
var _ref = this.schema || {}, | ||
filePath = _ref.filePath, | ||
schemaName = _ref.schemaName; | ||
var error = this.errorMessage || message; | ||
var prefix = ''; | ||
if (value === null) { | ||
invalid(state.nullable, 'Null is not allowed.', path); | ||
} // Run validations and produce a new value | ||
if (path) { | ||
prefix += schemaName ? "Invalid " + schemaName + " field \"" + path + "\"" : "Invalid field \"" + path + "\""; | ||
} else if (schemaName) { | ||
prefix += schemaName; | ||
} | ||
if (filePath) { | ||
prefix += " in " + filePath; | ||
const optimalError = new OptimalError(); | ||
validators.forEach(test => { | ||
if (test.skipIfNull && value === null || test.skipIfOptional && !state.required && value === state.defaultValue) { | ||
return; | ||
} | ||
tryAndCollect(() => { | ||
const result = test.validate(value, path, { | ||
collectErrors, | ||
currentObject, | ||
rootObject | ||
}); | ||
if (result !== undefined) { | ||
value = result; | ||
} | ||
}, optimalError, collectErrors); | ||
}); | ||
var nextError = prefix && !this.noErrorPrefix ? new Error(prefix + ". " + error) : new Error(error); | ||
throw nextError; | ||
} | ||
if (optimalError.errors.length > 0) { | ||
throw optimalError; | ||
} | ||
return value; | ||
} | ||
function createSchema({ | ||
api, | ||
cast, | ||
defaultValue, | ||
type | ||
}, criteria = []) { | ||
const state = { | ||
defaultValue, | ||
metadata: {}, | ||
never: false, | ||
nullable: false, | ||
required: false, | ||
type | ||
}; | ||
const validators = []; | ||
criteria.forEach(crit => { | ||
if (typeof crit === 'function') { | ||
const validator = crit(state); | ||
_proto.message = function message(_message) { | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(typeof _message === 'string' && !!_message, 'A non-empty string is required for custom messages.'); | ||
if (validator) { | ||
validators.push(validator); | ||
} | ||
} else { | ||
validators.push(crit); | ||
} | ||
}); | ||
const schema = { | ||
schema() { | ||
return type; | ||
}, | ||
this.errorMessage = _message; | ||
return this; | ||
}; | ||
type() { | ||
return state.type; | ||
}, | ||
_proto.never = function never() { | ||
this.defaultValue = undefined; | ||
this.isNever = true; | ||
return this; | ||
}; | ||
validate(value, path, options) { | ||
const result = validate(state, validators, value, path, options); | ||
return cast && result !== null ? cast(result) : result; | ||
} | ||
_proto.notNullable = function notNullable() { | ||
this.isNullable = false; | ||
return this; | ||
}; | ||
Object.entries(api).forEach(([name, method]) => { | ||
Object.defineProperty(schema, name, { | ||
enumerable: true, | ||
// Create a new schema so that our chainable API is immutable | ||
value: (...args) => createSchema({ | ||
api, | ||
cast, | ||
defaultValue, | ||
type | ||
}, [...criteria, nextState => method(nextState, ...args)]) | ||
}); | ||
}); | ||
return schema; | ||
} | ||
/** | ||
* Require field array to not be empty. | ||
*/ | ||
_proto.nullable = function nullable() { | ||
this.isNullable = true; | ||
return this; | ||
}; | ||
_proto.only = function only() { | ||
var _this3 = this; | ||
function notEmpty$2(state, options = {}) { | ||
return { | ||
skipIfNull: true, | ||
if ("production" !== process.env.NODE_ENV) { | ||
var defaultValue = this.default(); | ||
this.invariant(typeof defaultValue === this.type, "Only requires a default " + this.type + " value."); | ||
this.addCheck(function (path, value) { | ||
_this3.invariant(value === defaultValue, "Value may only be \"" + String(defaultValue) + "\".", path); | ||
}); | ||
validate(value, path) { | ||
invalid(value.length > 0, options.message ?? 'Array cannot be empty.', path, value); | ||
} | ||
return this; | ||
}; | ||
} | ||
/** | ||
* Require field array items to be of a specific schema type. | ||
* Will rebuild the array and type cast values. | ||
*/ | ||
_proto.or = function or() { | ||
var _this4 = this; | ||
for (var _len2 = arguments.length, keys = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
keys[_key2] = arguments[_key2]; | ||
} | ||
function of$5(state, itemsSchema) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isSchema(itemsSchema), 'A schema is required for array items.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(keys.length > 0, 'OR requires a list of field names.'); | ||
this.addCheck(function (path) { | ||
var _this4$schema$parentS, _this4$schema; | ||
state.type += `<${itemsSchema.type()}>`; | ||
return { | ||
skipIfNull: true, | ||
var orKeys = [_this4.key(path)].concat(keys); | ||
var struct = (_this4$schema$parentS = (_this4$schema = _this4.schema) == null ? void 0 : _this4$schema.parentStruct) != null ? _this4$schema$parentS : {}; | ||
var defs = orKeys.filter(function (key) { | ||
return typeof struct[key] !== 'undefined' && struct[key] !== null; | ||
}); | ||
validate(value, path, validateOptions) { | ||
if (!Array.isArray(value)) { | ||
return []; | ||
} | ||
_this4.invariant(defs.length > 0, "At least one of these fields must be defined: " + orKeys.join(', ')); | ||
const nextValue = [...value]; | ||
value.forEach((item, i) => { | ||
nextValue[i] = itemsSchema.validate(item, `${path}[${i}]`, validateOptions); | ||
}); | ||
return nextValue; | ||
} | ||
return this; | ||
}; | ||
} | ||
/** | ||
* Require field array to be of a specific size. | ||
*/ | ||
_proto.required = function required(state) { | ||
if (state === void 0) { | ||
state = true; | ||
} | ||
this.isRequired = state; | ||
return this; | ||
}; | ||
function sizeOf$2(state, size, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(typeof size === 'number' && size > 0, 'Size of requires a non-zero positive number.'); | ||
} | ||
_proto.run = function run(initialValue, path, schema) { | ||
this.schema = schema; | ||
this.defaultValue = this.default(); | ||
var value = initialValue; | ||
return { | ||
skipIfNull: true, | ||
if (value === undefined) { | ||
if (!this.isRequired) { | ||
value = this.defaultValue; | ||
} else if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(false, 'Field is required and must be defined.', path); | ||
} | ||
} else if ("production" !== process.env.NODE_ENV) { | ||
if (this.deprecatedMessage) { | ||
console.info("Field \"" + path + "\" is deprecated. " + this.deprecatedMessage); | ||
} | ||
if (this.isNever) { | ||
this.invariant(false, 'Field should never be used.', path); | ||
} | ||
validate(value, path) { | ||
invalid(value.length === size, options.message ?? `Array length must be ${size}.`, path, value); | ||
} | ||
if (value === null) { | ||
if (this.isNullable) { | ||
return null; | ||
} | ||
}; | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(false, 'Null is not allowed.', path); | ||
} | ||
} else { | ||
this.checkType(path, value); | ||
const arrayCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
notEmpty: notEmpty$2, | ||
of: of$5, | ||
sizeOf: sizeOf$2 | ||
}); | ||
/** | ||
* Require this field to only be false. | ||
*/ | ||
function onlyFalse(state, options = {}) { | ||
state.defaultValue = false; | ||
return { | ||
validate(value, path) { | ||
invalid(!value, options.message ?? 'May only be `false`.', path, value); | ||
} | ||
var finalValue = value; | ||
this.schema.currentPath = path; | ||
this.schema.currentValue = finalValue; | ||
finalValue = this.doRun(finalValue, path); | ||
finalValue = this.validate(finalValue, path); | ||
return this.cast(finalValue); | ||
}; | ||
} | ||
/** | ||
* Require this field to only be true. | ||
*/ | ||
_proto.typeAlias = function typeAlias() { | ||
return this.type; | ||
}; | ||
_proto.validate = function validate(value, path) { | ||
var _this5 = this; | ||
if (path === void 0) { | ||
path = ''; | ||
function onlyTrue(state, options = {}) { | ||
state.defaultValue = true; | ||
return { | ||
validate(value, path) { | ||
invalid(value, options.message ?? 'May only be `true`.', path, value); | ||
} | ||
var nextValue = value; | ||
this.checkType(path, value); | ||
this.checks.forEach(function (checker) { | ||
var result = checker.call(_this5, path, nextValue); | ||
if (typeof result !== 'undefined') { | ||
nextValue = result; | ||
} | ||
}); | ||
return nextValue; | ||
}; | ||
} | ||
_proto.xor = function xor() { | ||
var _this6 = this; | ||
const booleanCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
onlyFalse: onlyFalse, | ||
onlyTrue: onlyTrue | ||
}); | ||
/** | ||
* Require this field to be an instance of the defined class. | ||
*/ | ||
for (var _len3 = arguments.length, keys = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
keys[_key3] = arguments[_key3]; | ||
} | ||
function of$4(state, ref, loose = false) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(typeof ref === 'function', 'A class reference is required.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(keys.length > 0, 'XOR requires a list of field names.'); | ||
this.addCheck(function (path) { | ||
var _this6$schema$parentS, _this6$schema; | ||
state.type = ref.name ?? ref.constructor.name; | ||
return { | ||
skipIfNull: true, | ||
var xorKeys = [_this6.key(path)].concat(keys); | ||
var struct = (_this6$schema$parentS = (_this6$schema = _this6.schema) == null ? void 0 : _this6$schema.parentStruct) != null ? _this6$schema$parentS : {}; | ||
var defs = xorKeys.filter(function (key) { | ||
return typeof struct[key] !== 'undefined' && struct[key] !== null; | ||
}); | ||
_this6.invariant(defs.length === 1, "Only one of these fields may be defined: " + xorKeys.join(', ')); | ||
}); | ||
validate(value, path) { | ||
invalid(typeof ref === 'function' && (value instanceof ref || loose && isObject(value) && instanceOf(value, ref)), `Must be an instance of "${state.type}".`, path, value); | ||
} | ||
return this; | ||
}; | ||
} | ||
_proto.addCheck = function addCheck(checker) { | ||
this.checks.push(checker); | ||
return this; | ||
}; | ||
const classCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
of: of$4 | ||
}); | ||
/** | ||
* Map a list of field names that must be defined alongside this field. | ||
*/ | ||
_proto.checkType = function checkType(path, value) { | ||
if ("production" !== process.env.NODE_ENV) { | ||
var displayValue = this.extractDisplayValue(value); | ||
function and(state, ...keys) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(keys.length > 0, 'AND requires a list of field names.'); | ||
} | ||
switch (this.type) { | ||
case 'array': | ||
case 'tuple': | ||
this.invariant(Array.isArray(value), "Must be an array, received " + displayValue + ".", path); | ||
break; | ||
return { | ||
validate(value, path, { | ||
currentObject | ||
}) { | ||
const andKeys = [...new Set([pathKey(path), ...keys])].sort(); | ||
const undefs = andKeys.filter(key => currentObject?.[key] === undefined || currentObject?.[key] === null); // Only error once when one of the struct is defined | ||
case 'custom': | ||
case 'instance': | ||
case 'union': | ||
break; | ||
if (undefs.length === andKeys.length) { | ||
return; | ||
} | ||
case 'object': | ||
case 'shape': | ||
this.invariant(isObject(value), "Must be a plain object, received " + displayValue + ".", path); | ||
break; | ||
invalid(undefs.length === 0, `All of these fields must be defined: ${andKeys.join(', ')}`); | ||
} | ||
default: | ||
this.invariant(typeof value === this.type, "Must be a " + this.type + ", received " + displayValue + ".", path); | ||
break; | ||
} | ||
} | ||
}; | ||
} | ||
/** | ||
* Set a callback to run custom validation logic. | ||
*/ | ||
_proto.extractDisplayValue = function extractDisplayValue(value) { | ||
var type = typeOf(value); | ||
var displayValue = ''; | ||
if (type === 'string') { | ||
displayValue = "\"" + value + "\""; | ||
} else if (type === 'number' || type === 'boolean' || value === null || value === undefined) { | ||
displayValue = String(value); | ||
} else { | ||
displayValue = type; | ||
function custom$1(state, validator) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(typeof validator === 'function', 'Custom requires a validation function.'); | ||
} | ||
return { | ||
validate(value, path, validateOptions) { | ||
try { | ||
validator(value, path, validateOptions); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
invalid(false, error.message, path, value); | ||
} | ||
} | ||
} | ||
return displayValue; | ||
}; | ||
} | ||
/** | ||
* Set a message to log when this field is present. | ||
*/ | ||
_proto.isOptionalDefault = function isOptionalDefault(value) { | ||
return !this.isRequired && value === this.default(); | ||
}; | ||
_proto.key = function key(path) { | ||
var index = path.lastIndexOf('.'); | ||
return index > 0 ? path.slice(index + 1) : path; | ||
}; | ||
function deprecate(state, message) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isValidString(message), 'A non-empty string is required for deprecated messages.'); | ||
} | ||
_proto.doRun = function doRun(value, path) { | ||
return value; | ||
}; | ||
state.metadata.deprecatedMessage = message; | ||
} | ||
/** | ||
* Mark that this field should never be used. | ||
*/ | ||
return Predicate; | ||
}(); | ||
function custom(callback, defaultValue) { | ||
return new Predicate('custom', defaultValue).custom(callback); | ||
function never(state) { | ||
state.defaultValue = undefined; | ||
state.never = true; | ||
} | ||
function func(defaultValue) { | ||
if (defaultValue === void 0) { | ||
defaultValue = null; | ||
} | ||
/** | ||
* Disallow null values. | ||
*/ | ||
return new Predicate('function', defaultValue, true).nullable(); | ||
function notNullable(state) { | ||
state.nullable = false; | ||
} | ||
/** | ||
* Require this field to NOT be explicitly defined. | ||
*/ | ||
var Schema = function () { | ||
function Schema(blueprint) { | ||
this.blueprint = void 0; | ||
this.currentPath = ''; | ||
this.currentValue = null; | ||
this.filePath = ''; | ||
this.initialStruct = {}; | ||
this.parentPath = ''; | ||
this.parentStruct = {}; | ||
this.struct = {}; | ||
this.schemaName = ''; | ||
this.unknown = false; | ||
if ("production" !== process.env.NODE_ENV) { | ||
if (!isObject(blueprint)) { | ||
throw new TypeError('A schema blueprint is required.'); | ||
} | ||
} | ||
function notRequired(state) { | ||
state.required = false; | ||
} | ||
/** | ||
* Allow null values. | ||
*/ | ||
this.blueprint = blueprint; | ||
} | ||
var _proto = Schema.prototype; | ||
function nullable(state) { | ||
state.nullable = true; | ||
} | ||
/** | ||
* Mark that this field can ONLY use a value that matches the default value. | ||
*/ | ||
_proto.allowUnknown = function allowUnknown() { | ||
this.unknown = true; | ||
return this; | ||
}; | ||
_proto.build = function build(struct, pathPrefix) { | ||
var _this = this; | ||
function only(state) { | ||
const { | ||
defaultValue | ||
} = state; | ||
if (pathPrefix === void 0) { | ||
pathPrefix = ''; | ||
} | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(defaultValue !== null && defaultValue !== undefined, 'Only requires a non-empty default value.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
if (!isObject(struct)) { | ||
throw new TypeError("Schema requires a plain object, found " + typeOf(struct) + "."); | ||
} | ||
return { | ||
validate(value, path) { | ||
invalid(value === defaultValue, `Value may only be "${defaultValue}".`, path, value); | ||
} | ||
this.initialStruct = _extends({}, struct); | ||
this.struct = _extends({}, struct); | ||
}; | ||
} | ||
/** | ||
* Map a list of field names that must have at least 1 defined. | ||
*/ | ||
var unknownFields = _extends({}, struct); | ||
Object.keys(this.blueprint).forEach(function (baseKey) { | ||
var key = baseKey; | ||
var value = struct[key]; | ||
var predicate = _this.blueprint[key]; | ||
var path = String(pathPrefix ? pathPrefix + "." + key : key); | ||
function or(state, ...keys) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(keys.length > 0, 'OR requires a list of field names.'); | ||
} | ||
if (predicate instanceof Predicate || isObject(predicate) && predicate.constructor.name.endsWith('Predicate')) { | ||
_this.parentPath = baseKey; | ||
_this.parentStruct = _this.initialStruct; | ||
_this.struct[key] = predicate.run(value, path, _this); | ||
} else if ("production" !== process.env.NODE_ENV) { | ||
throw new Error("Unknown blueprint for \"" + path + "\". Must be a predicate."); | ||
} | ||
delete unknownFields[key]; | ||
}); | ||
if (this.unknown) { | ||
Object.assign(this.struct, unknownFields); | ||
} else if ("production" !== process.env.NODE_ENV) { | ||
logUnknown(unknownFields, pathPrefix); | ||
return { | ||
validate(value, path, { | ||
currentObject | ||
}) { | ||
const orKeys = [...new Set([pathKey(path), ...keys])].sort(); | ||
const defs = orKeys.filter(key => currentObject?.[key] !== undefined && currentObject?.[key] !== null); | ||
invalid(defs.length > 0, `At least one of these fields must be defined: ${orKeys.join(', ')}`); | ||
} | ||
return this.struct; | ||
}; | ||
} | ||
/** | ||
* Require this field to be explicitly defined. | ||
*/ | ||
_proto.setFile = function setFile(name) { | ||
this.filePath = name; | ||
return this; | ||
}; | ||
_proto.setName = function setName(name) { | ||
this.schemaName = name; | ||
return this; | ||
}; | ||
function required(state) { | ||
state.required = true; | ||
} | ||
/** | ||
* TODO | ||
*/ | ||
return Schema; | ||
}(); | ||
function optimal(struct, blueprint, options) { | ||
if (options === void 0) { | ||
options = {}; | ||
function when(state, condition, pass, fail) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isSchema(pass), 'A schema is required when the condition passes.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
if (!isObject(options)) { | ||
throw new TypeError('Optimal options must be a plain object.'); | ||
if (fail !== undefined) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isSchema(fail), 'A schema is required when the condition fails.'); | ||
} | ||
} | ||
var schema = new Schema(blueprint); | ||
return { | ||
validate(value, path, validateOptions) { | ||
const passed = typeof condition === 'function' ? condition(value, validateOptions.currentObject, validateOptions.rootObject) : condition === value; | ||
if (options.name) { | ||
schema.setName(options.name); | ||
} | ||
if (passed) { | ||
return pass.validate(value, path); | ||
} | ||
if (options.file) { | ||
schema.setFile(options.file); | ||
} | ||
if (fail) { | ||
return fail.validate(value, path, validateOptions); | ||
} | ||
if (options.unknown) { | ||
schema.allowUnknown(); | ||
} | ||
return undefined; | ||
} | ||
return schema.build(struct, options.prefix); | ||
}; | ||
} | ||
/** | ||
* Map a list of field names that must not be defined alongside this field. | ||
*/ | ||
var CollectionPredicate = function (_Predicate) { | ||
_inheritsLoose(CollectionPredicate, _Predicate); | ||
function CollectionPredicate() { | ||
return _Predicate.apply(this, arguments) || this; | ||
function xor(state, ...keys) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(keys.length > 0, 'XOR requires a list of field names.'); | ||
} | ||
var _proto = CollectionPredicate.prototype; | ||
_proto.sizeOf = function sizeOf(length) { | ||
var _this = this; | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(typeof length === 'number' && length > 0, 'Size requires a non-zero positive number.'); | ||
this.addCheck(function (path, value) { | ||
if (_this.isNullable && value === null) { | ||
return; | ||
} | ||
if (Array.isArray(value)) { | ||
_this.invariant(value.length === length, "Array length must be " + length + ".", path); | ||
} else if (typeof value === 'string') { | ||
_this.invariant(value.length === length, "String length must be " + length + ".", path); | ||
} else if (typeof value === 'object' && value) { | ||
_this.invariant(Object.keys(value).length === length, "Object must have " + length + " properties.", path); | ||
} else { | ||
_this.invariant(false, 'Unknown type for size of checks.', path); | ||
} | ||
}); | ||
return { | ||
validate(value, path, { | ||
currentObject | ||
}) { | ||
const xorKeys = [...new Set([pathKey(path), ...keys])].sort(); | ||
const defs = xorKeys.filter(key => currentObject?.[key] !== undefined && currentObject?.[key] !== null); | ||
invalid(defs.length === 1, `Only one of these fields may be defined: ${xorKeys.join(', ')}`); | ||
} | ||
return this; | ||
}; | ||
} | ||
return CollectionPredicate; | ||
}(Predicate); | ||
const commonCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
and: and, | ||
custom: custom$1, | ||
deprecate: deprecate, | ||
never: never, | ||
notNullable: notNullable, | ||
notRequired: notRequired, | ||
nullable: nullable, | ||
only: only, | ||
or: or, | ||
required: required, | ||
when: when, | ||
xor: xor | ||
}); | ||
/** | ||
* Require field value to be after the provided date. | ||
*/ | ||
var ArrayPredicate = function (_CollectionPredicate) { | ||
_inheritsLoose(ArrayPredicate, _CollectionPredicate); | ||
function after(state, date, options = {}) { | ||
const afterDate = createDate(date); | ||
function ArrayPredicate(contents, defaultValue) { | ||
var _this; | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isValidDate(afterDate), 'After date must be a valid date.'); | ||
} | ||
if (contents === void 0) { | ||
contents = null; | ||
} | ||
return { | ||
skipIfNull: true, | ||
if (defaultValue === void 0) { | ||
defaultValue = []; | ||
validate(value, path) { | ||
invalid(isValidDate(value) && value > afterDate, options.message ?? `Date must come after ${afterDate.toLocaleDateString()}.`, path, value); | ||
} | ||
_this = _CollectionPredicate.call(this, 'array', defaultValue) || this; | ||
_this.contents = null; | ||
_this.contents = contents; | ||
}; | ||
} | ||
/** | ||
* Require field value to be before the provided date. | ||
*/ | ||
if (contents instanceof Predicate) { | ||
_this.addCheck(function (path, value) { | ||
var nextValue = [].concat(value); | ||
value.forEach(function (item, i) { | ||
nextValue[i] = contents.run(item, path + "[" + i + "]", _this.schema); | ||
}); | ||
return nextValue; | ||
}); | ||
} else if ("production" !== process.env.NODE_ENV && contents) { | ||
_this.invariant(false, 'A blueprint is required for array contents.'); | ||
} | ||
return _this; | ||
function before(state, date, options = {}) { | ||
const beforeDate = createDate(date); | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isValidDate(beforeDate), 'Before date must be a valid date.'); | ||
} | ||
var _proto = ArrayPredicate.prototype; | ||
return { | ||
skipIfNull: true, | ||
_proto.cast = function cast(value) { | ||
if (value === undefined) { | ||
return []; | ||
validate(value, path) { | ||
invalid(isValidDate(value) && value < beforeDate, options.message ?? `Date must come before ${beforeDate.toLocaleDateString()}.`, path, value); | ||
} | ||
return Array.isArray(value) ? value : [value]; | ||
}; | ||
} | ||
/** | ||
* Require field value to be between 2 date ranges. | ||
*/ | ||
_proto.notEmpty = function notEmpty() { | ||
var _this2 = this; | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
if (_this2.isNullable && value === null) { | ||
return; | ||
} | ||
function between$1(state, start, end, options = {}) { | ||
const startDate = createDate(start); | ||
const endDate = createDate(end); | ||
_this2.invariant(value.length > 0, 'Array cannot be empty.', path); | ||
}); | ||
} | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isValidDate(startDate), 'Between start date must be a valid date.'); | ||
} | ||
return this; | ||
}; | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isValidDate(endDate), 'Between end date must be a valid date.'); | ||
} | ||
_proto.typeAlias = function typeAlias() { | ||
var contents = this.contents; | ||
return { | ||
skipIfNull: true, | ||
var alias = _CollectionPredicate.prototype.typeAlias.call(this); | ||
validate(value, path) { | ||
invalid(isValidDate(value) && (options.inclusive ? value >= startDate && value <= endDate : value > startDate && value < endDate), options.message ?? `Date must be between ${startDate.toLocaleDateString()} and ${endDate.toLocaleDateString()}${options.inclusive ? ' inclusive' : ''}.`, path, value); | ||
} | ||
return contents ? alias + "<" + contents.typeAlias() + ">" : alias; | ||
}; | ||
return ArrayPredicate; | ||
}(CollectionPredicate); | ||
function array(contents, defaultValue) { | ||
if (contents === void 0) { | ||
contents = null; | ||
} | ||
return new ArrayPredicate(contents, defaultValue); | ||
} | ||
var BooleanPredicate = function (_Predicate) { | ||
_inheritsLoose(BooleanPredicate, _Predicate); | ||
const dateCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
after: after, | ||
before: before, | ||
between: between$1 | ||
}); | ||
/** | ||
* Require field value to be between 2 numbers. | ||
*/ | ||
function BooleanPredicate(defaultValue) { | ||
return _Predicate.call(this, 'boolean', defaultValue) || this; | ||
function between(state, min, max, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isValidNumber(min) && isValidNumber(max), 'Between requires a minimum and maximum number.'); | ||
} | ||
var _proto = BooleanPredicate.prototype; | ||
return { | ||
skipIfNull: true, | ||
_proto.cast = function cast(value) { | ||
return Boolean(value); | ||
}; | ||
_proto.onlyFalse = function onlyFalse() { | ||
var _this = this; | ||
this.defaultValue = false; | ||
this.defaultValueFactory = undefined; | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
_this.invariant(value === false, 'May only be `false`.', path); | ||
}); | ||
validate(value, path) { | ||
invalid(isValidNumber(value) && (options.inclusive ? value >= min && value <= max : value > min && value < max), options.message ?? `Number must be between ${min} and ${max}${options.inclusive ? ' inclusive' : ''}.`, path, value); | ||
} | ||
return this; | ||
}; | ||
} | ||
/** | ||
* Require field value to be a float (includes a decimal). | ||
*/ | ||
_proto.onlyTrue = function onlyTrue() { | ||
var _this2 = this; | ||
this.defaultValue = true; | ||
this.defaultValueFactory = undefined; | ||
function float(state, options = {}) { | ||
return { | ||
skipIfNull: true, | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
_this2.invariant(value === true, 'May only be `true`.', path); | ||
}); | ||
validate(value, path) { | ||
invalid(isValidNumber(value) && value % 1 !== 0, options.message ?? 'Number must be a float.', path, value); | ||
} | ||
return this; | ||
}; | ||
return BooleanPredicate; | ||
}(Predicate); | ||
function bool(defaultValue) { | ||
if (defaultValue === void 0) { | ||
defaultValue = false; | ||
} | ||
return new BooleanPredicate(defaultValue); | ||
} | ||
/** | ||
* Require field value to be greater than a number. | ||
*/ | ||
function instanceOf(object, contract) { | ||
if (!object || typeof object !== 'object') { | ||
return false; | ||
} | ||
if (object instanceof contract) { | ||
return true; | ||
function gt(state, min, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isValidNumber(min), 'Greater-than requires a minimum number.'); | ||
} | ||
var current = object; | ||
return { | ||
skipIfNull: true, | ||
while (current) { | ||
if (current.constructor.name === 'Object') { | ||
return false; | ||
validate(value, path) { | ||
if (options.inclusive) { | ||
invalid(isValidNumber(value) && value >= min, options.message ?? `Number must be greater than or equal to ${min}.`, path, value); | ||
} else { | ||
invalid(isValidNumber(value) && value > min, options.message ?? `Number must be greater than ${min}.`, path, value); | ||
} | ||
} | ||
if (current.constructor.name === contract.name || current instanceof Error && current.name === contract.name) { | ||
return true; | ||
} | ||
}; | ||
} | ||
/** | ||
* Require field value to be greater than or equals to a number. | ||
*/ | ||
current = Object.getPrototypeOf(current); | ||
} | ||
return false; | ||
function gte(state, min, options = {}) { | ||
return gt(state, min, { ...options, | ||
inclusive: true | ||
}); | ||
} | ||
/** | ||
* Require field value to be an integer. | ||
*/ | ||
var InstancePredicate = function (_Predicate) { | ||
_inheritsLoose(InstancePredicate, _Predicate); | ||
function InstancePredicate(refClass, loose) { | ||
var _this; | ||
function int(state, options = {}) { | ||
return { | ||
skipIfNull: true, | ||
if (refClass === void 0) { | ||
refClass = null; | ||
validate(value, path) { | ||
invalid(Number.isSafeInteger(value), options.message ?? 'Number must be an integer.', path, value); | ||
} | ||
if (loose === void 0) { | ||
loose = false; | ||
} | ||
}; | ||
} | ||
/** | ||
* Require field value to be less than a number. | ||
*/ | ||
_this = _Predicate.call(this, 'instance', null) || this; | ||
_this.loose = false; | ||
_this.refClass = null; | ||
_this.nullable(); | ||
function lt(state, max, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isValidNumber(max), 'Less-than requires a maximum number.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
if (refClass) { | ||
_this.invariant(typeof refClass === 'function', 'A class reference is required.'); | ||
return { | ||
skipIfNull: true, | ||
validate(value, path) { | ||
if (options.inclusive) { | ||
invalid(isValidNumber(value) && value <= max, options.message ?? `Number must be less than or equal to ${max}.`, path, value); | ||
} else { | ||
invalid(isValidNumber(value) && value < max, options.message ?? `Number must be less than ${max}.`, path, value); | ||
} | ||
} | ||
_this.loose = loose; | ||
_this.refClass = refClass; | ||
}; | ||
} | ||
/** | ||
* Require field value to be less than or equals to a number. | ||
*/ | ||
_this.addCheck(function (path, value) { | ||
if (refClass) { | ||
_this.invariant(typeof refClass === 'function' && (value instanceof refClass || _this.loose && isObject(value) && instanceOf(value, refClass)), "Must be an instance of \"" + _this.typeAlias() + "\".", path); | ||
} else { | ||
_this.invariant(isObject(value) && value.constructor.name !== 'Object', 'Must be a class instance.', path); | ||
} | ||
}); | ||
} | ||
return _this; | ||
} | ||
function lte(state, max, options = {}) { | ||
return lt(state, max, { ...options, | ||
inclusive: true | ||
}); | ||
} | ||
/** | ||
* Require field value to be negative and not zero. | ||
*/ | ||
var _proto = InstancePredicate.prototype; | ||
_proto.typeAlias = function typeAlias() { | ||
var refClass = this.refClass; | ||
return refClass ? refClass.name || refClass.constructor.name : 'class'; | ||
}; | ||
function negative(state, options = {}) { | ||
return { | ||
skipIfNull: true, | ||
return InstancePredicate; | ||
}(Predicate); | ||
function instance(refClass, loose) { | ||
if (refClass === void 0) { | ||
refClass = null; | ||
} | ||
validate(value, path) { | ||
invalid(isValidNumber(value) && value < 0, options.message ?? 'Number must be negative.', path, value); | ||
} | ||
return new InstancePredicate(refClass, loose); | ||
}; | ||
} | ||
function predicate() { | ||
return instance(Predicate); | ||
} | ||
function regex() { | ||
return instance(RegExp); | ||
} | ||
function date() { | ||
return instance(Date); | ||
} | ||
/** | ||
* Require field value to be one of the provided numbers. | ||
*/ | ||
function isNumber(value) { | ||
return typeof value === 'number' && !Number.isNaN(value); | ||
} | ||
var NumberPredicate = function (_Predicate) { | ||
_inheritsLoose(NumberPredicate, _Predicate); | ||
function NumberPredicate(defaultValue) { | ||
return _Predicate.call(this, 'number', defaultValue) || this; | ||
function oneOf$1(state, list, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(Array.isArray(list) && list.length > 0 && list.every(item => isValidNumber(item)), 'One of requires an array of numbers.'); | ||
} | ||
var _proto = NumberPredicate.prototype; | ||
return { | ||
skipIfNull: true, | ||
_proto.between = function between(min, max, inclusive) { | ||
var _this = this; | ||
if (inclusive === void 0) { | ||
inclusive = false; | ||
validate(value, path) { | ||
invalid(list.includes(value), options.message ?? `Number must be one of: ${list.join(', ')}`, path, value); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(isNumber(min) && isNumber(max), 'Between requires a minimum and maximum number.'); | ||
this.addCheck(function (path, value) { | ||
_this.invariant(isNumber(value) && (inclusive ? value >= min && value <= max : value > min && value < max), "Number must be between " + min + " and " + max + (inclusive ? ' inclusive' : '') + ".", path); | ||
}); | ||
} | ||
return this; | ||
}; | ||
} | ||
/** | ||
* Require field value to be positive and not zero. | ||
*/ | ||
_proto.cast = function cast(value) { | ||
return value === undefined ? 0 : Number(value); | ||
}; | ||
_proto.float = function float() { | ||
var _this2 = this; | ||
function positive(state, options = {}) { | ||
return { | ||
skipIfNull: true, | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
_this2.invariant(isNumber(value) && value % 1 !== 0, 'Number must be a float.', path); | ||
}); | ||
validate(value, path) { | ||
invalid(isValidNumber(value) && value > 0, options.message ?? 'Number must be positive.', path, value); | ||
} | ||
return this; | ||
}; | ||
} | ||
_proto.gt = function gt(min, inclusive) { | ||
var _this3 = this; | ||
const numberCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
between: between, | ||
float: float, | ||
gt: gt, | ||
gte: gte, | ||
int: int, | ||
lt: lt, | ||
lte: lte, | ||
negative: negative, | ||
oneOf: oneOf$1, | ||
positive: positive | ||
}); | ||
/** | ||
* Require field object keys to be of a string schema type. | ||
*/ | ||
if (inclusive === void 0) { | ||
inclusive = false; | ||
} | ||
function keysOf(state, keysSchema, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isSchema(keysSchema) && keysSchema.schema() === 'string', 'A string schema is required for object keys.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(isNumber(min), 'Greater-than requires a minimum number.'); | ||
this.addCheck(function (path, value) { | ||
if (inclusive) { | ||
_this3.invariant(isNumber(value) && value >= min, "Number must be greater than or equal to " + min + ".", path); | ||
} else { | ||
_this3.invariant(isNumber(value) && value > min, "Number must be greater than " + min + ".", path); | ||
} | ||
}); | ||
return { | ||
skipIfNull: true, | ||
validate(value, path, validateOptions) { | ||
if (isObject(value)) { | ||
Object.keys(value).forEach(key => { | ||
try { | ||
// Dont pass path so its not included in the error message | ||
keysSchema.validate(key, '', validateOptions); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
invalid(false, `Invalid key "${key}". ${options.message ?? error.message}`, path, value); | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
return this; | ||
}; | ||
} | ||
/** | ||
* Require field object to not be empty. | ||
*/ | ||
_proto.gte = function gte(min) { | ||
return this.gt(min, true); | ||
}; | ||
_proto.int = function int() { | ||
var _this4 = this; | ||
function notEmpty$1(state, options = {}) { | ||
return { | ||
skipIfNull: true, | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
_this4.invariant(Number.isSafeInteger(value), 'Number must be an integer.', path); | ||
}); | ||
validate(value, path) { | ||
invalid(Object.keys(value).length > 0, options.message ?? 'Object cannot be empty.', path, value); | ||
} | ||
return this; | ||
}; | ||
} | ||
/** | ||
* Require field object values to be of a specific schema type. | ||
* Will rebuild the object and type cast values. | ||
*/ | ||
_proto.lt = function lt(max, inclusive) { | ||
var _this5 = this; | ||
if (inclusive === void 0) { | ||
inclusive = false; | ||
} | ||
function of$3(state, valuesSchema) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isSchema(valuesSchema), 'A schema is required for object values.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(isNumber(max), 'Less-than requires a maximum number.'); | ||
this.addCheck(function (path, value) { | ||
if (inclusive) { | ||
_this5.invariant(isNumber(value) && value <= max, "Number must be less than or equal to " + max + ".", path); | ||
} else { | ||
_this5.invariant(isNumber(value) && value < max, "Number must be less than " + max + ".", path); | ||
} | ||
state.type += `<${valuesSchema.type()}>`; | ||
return { | ||
skipIfNull: true, | ||
validate(value, path, validateOptions) { | ||
if (!isObject(value)) { | ||
return {}; | ||
} | ||
const nextValue = { ...value | ||
}; | ||
Object.keys(value).forEach(baseKey => { | ||
const key = baseKey; | ||
nextValue[key] = valuesSchema.validate(value[key], path ? `${path}.${key}` : String(key), validateOptions); | ||
}); | ||
return nextValue; | ||
} | ||
return this; | ||
}; | ||
} | ||
/** | ||
* Require field object to be of a specific size. | ||
*/ | ||
_proto.lte = function lte(max) { | ||
return this.lt(max, true); | ||
}; | ||
_proto.negative = function negative() { | ||
var _this6 = this; | ||
function sizeOf$1(state, size, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(typeof size === 'number' && size > 0, 'Size of requires a non-zero positive number.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
_this6.invariant(isNumber(value) && value < 0, 'Number must be negative.', path); | ||
}); | ||
return { | ||
skipIfNull: true, | ||
validate(value, path) { | ||
invalid(Object.keys(value).length === size, options.message ?? (size === 1 ? `Object must have ${size} property.` : `Object must have ${size} properties.`), path, value); | ||
} | ||
return this; | ||
}; | ||
} | ||
_proto.oneOf = function oneOf(list) { | ||
var _this7 = this; | ||
const objectCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
keysOf: keysOf, | ||
notEmpty: notEmpty$1, | ||
of: of$3, | ||
sizeOf: sizeOf$1 | ||
}); | ||
/** | ||
* Require a shape to be an exact shape. | ||
* No more and no less of the same properties. | ||
*/ | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(Array.isArray(list) && list.length > 0 && list.every(function (item) { | ||
return isNumber(item); | ||
}), 'One of requires a non-empty array of numbers.'); | ||
this.addCheck(function (path, value) { | ||
_this7.invariant(list.includes(value), "Number must be one of: " + list.join(', '), path); | ||
}); | ||
} | ||
function exact(state, value = true) { | ||
state.metadata.exact = value; | ||
} | ||
/** | ||
* Require field to be an object with every property being a schema type. | ||
* Will rebuild the object (if not a class instance) and type cast values. | ||
*/ | ||
return this; | ||
}; | ||
_proto.positive = function positive() { | ||
var _this8 = this; | ||
function of$2(state, schemas) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isObject(schemas) && Object.keys(schemas).length > 0 && Object.values(schemas).every(isSchema), 'A non-empty object of schemas are required for a shape.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
_this8.invariant(isNumber(value) && value > 0, 'Number must be positive.', path); | ||
const types = Object.entries(schemas).map(([key, value]) => `${key}: ${value.type()}`); | ||
state.type += `<{ ${types.join(', ')} }>`; | ||
return { | ||
skipIfNull: true, | ||
validate(value, path, validateOptions) { | ||
if (value) { | ||
invalid(isObject(value), 'Value passed to shape must be an object.', path, value); | ||
} | ||
const isPlainObject = value.constructor === Object; | ||
const unknown = isPlainObject ? { ...value | ||
} : {}; | ||
const shape = {}; | ||
const collectionError = new ValidationError('The following validations have failed:', path, value); | ||
Object.keys(schemas).forEach(prop => { | ||
const key = prop; | ||
const schema = schemas[key]; | ||
tryAndCollect(() => { | ||
shape[key] = schema.validate(value[key], path ? `${path}.${key}` : String(key), { ...validateOptions, | ||
currentObject: value | ||
}); | ||
}, collectionError, validateOptions.collectErrors); // Delete the prop and mark it as known | ||
delete unknown[key]; | ||
}); | ||
} | ||
return this; | ||
}; | ||
if (collectionError.errors.length > 0) { | ||
throw collectionError; | ||
} // Handle unknown fields | ||
return NumberPredicate; | ||
}(Predicate); | ||
function number(defaultValue) { | ||
return new NumberPredicate(defaultValue); | ||
} | ||
var ObjectPredicate = function (_CollectionPredicate) { | ||
_inheritsLoose(ObjectPredicate, _CollectionPredicate); | ||
if (state.metadata.exact) { | ||
if (process.env.NODE_ENV !== "production") { | ||
logUnknown(unknown, path); | ||
} | ||
} else { | ||
Object.assign(shape, unknown); | ||
} // Dont replace class instance with plain objects | ||
function ObjectPredicate(contents, defaultValue) { | ||
var _this; | ||
if (contents === void 0) { | ||
contents = null; | ||
return isPlainObject ? shape : value; | ||
} | ||
_this = _CollectionPredicate.call(this, 'object', defaultValue) || this; | ||
_this.contents = null; | ||
_this.contents = contents; | ||
}; | ||
} | ||
if (contents instanceof Predicate) { | ||
_this.addCheck(function (path, value) { | ||
var nextValue = _extends({}, value); | ||
const shapeCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
exact: exact, | ||
of: of$2 | ||
}); | ||
/** | ||
* Require field value to contain a provided string. | ||
*/ | ||
Object.keys(value).forEach(function (baseKey) { | ||
var key = baseKey; | ||
nextValue[key] = contents.run(value[key], path + "." + key, _this.schema); | ||
}); | ||
return nextValue; | ||
}); | ||
} else if ("production" !== process.env.NODE_ENV && contents) { | ||
_this.invariant(false, 'A blueprint is required for object contents.'); | ||
} | ||
return _this; | ||
function contains(state, token, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isValidString(token), 'Contains requires a non-empty token.'); | ||
} | ||
var _proto = ObjectPredicate.prototype; | ||
return { | ||
skipIfNull: true, | ||
skipIfOptional: true, | ||
_proto.cast = function cast(value) { | ||
var obj = isObject(value) ? value : {}; | ||
return obj; | ||
validate(value, path) { | ||
invalid(value.includes(token, options.index ?? 0), options.message ?? `String does not include "${token}".`, path, value); | ||
} | ||
}; | ||
} | ||
/** | ||
* Require field value to match a defined regex pattern. | ||
*/ | ||
_proto.notEmpty = function notEmpty() { | ||
var _this2 = this; | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
if (_this2.isNullable && value === null) { | ||
return; | ||
} | ||
function match(state, pattern, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(pattern instanceof RegExp, 'Match requires a regular expression to match against.'); | ||
} | ||
_this2.invariant(Object.keys(value).length > 0, 'Object cannot be empty.', path); | ||
}); | ||
return { | ||
skipIfNull: true, | ||
skipIfOptional: true, | ||
validate(value, path) { | ||
invalid(!!value.match(pattern), `${options.message ?? 'String does not match.'} (pattern "${pattern.source}")`, path, value); | ||
} | ||
return this; | ||
}; | ||
} | ||
/** | ||
* Require field value to be formatted in camel case (fooBar). | ||
*/ | ||
_proto.typeAlias = function typeAlias() { | ||
var contents = this.contents; | ||
var alias = _CollectionPredicate.prototype.typeAlias.call(this); | ||
function camelCase(state, options = {}) { | ||
return match(state, /^[a-z][a-zA-Z0-9]+$/u, { | ||
message: 'String must be in camel case.', | ||
...options | ||
}); | ||
} | ||
/** | ||
* Require field value to be formatted in kebab case (foo-bar). | ||
*/ | ||
return contents ? alias + "<" + contents.typeAlias() + ">" : alias; | ||
}; | ||
return ObjectPredicate; | ||
}(CollectionPredicate); | ||
function object(contents, defaultValue) { | ||
if (contents === void 0) { | ||
contents = null; | ||
} | ||
function kebabCase(state, options = {}) { | ||
return match(state, /^[a-z][a-z0-9-]+$/u, { | ||
message: 'String must be in kebab case.', | ||
...options | ||
}); | ||
} | ||
/** | ||
* Require field value to be formatted in pascal case (FooBar). | ||
*/ | ||
return new ObjectPredicate(contents, defaultValue); | ||
function pascalCase(state, options = {}) { | ||
return match(state, /^[A-Z][a-zA-Z0-9]+$/u, { | ||
message: 'String must be in pascal case.', | ||
...options | ||
}); | ||
} | ||
function blueprint(defaultValue) { | ||
return new ObjectPredicate(predicate().notNullable(), defaultValue); | ||
/** | ||
* Require field value to be formatted in snake case (foo_bar). | ||
*/ | ||
function snakeCase(state, options = {}) { | ||
return match(state, /^[a-z][a-z0-9_]+$/u, { | ||
message: 'String must be in snake case.', | ||
...options | ||
}); | ||
} | ||
/** | ||
* Require field value to not be an empty string. | ||
*/ | ||
var ShapePredicate = function (_Predicate) { | ||
_inheritsLoose(ShapePredicate, _Predicate); | ||
function ShapePredicate(contents) { | ||
var _this; | ||
function notEmpty(state, options = {}) { | ||
return { | ||
skipIfNull: true, | ||
_this = _Predicate.call(this, 'shape', {}) || this; | ||
_this.contents = void 0; | ||
_this.isExact = false; | ||
if ("production" !== process.env.NODE_ENV) { | ||
_this.invariant(isObject(contents) && Object.keys(contents).length > 0 && Object.values(contents).every(function (content) { | ||
return content instanceof Predicate; | ||
}), 'A non-empty object of properties to blueprints are required for a shape.'); | ||
validate(value, path) { | ||
invalid(isValidString(value), options.message ?? 'String cannot be empty.', path, value); | ||
} | ||
_this.contents = contents; | ||
return _this; | ||
}; | ||
} | ||
/** | ||
* Require field value to be one of the provided string. | ||
*/ | ||
function oneOf(state, list, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(Array.isArray(list) && list.length > 0 && list.every(item => typeof item === 'string'), 'One of requires an array of strings.'); | ||
} | ||
var _proto = ShapePredicate.prototype; | ||
return { | ||
skipIfNull: true, | ||
_proto.default = function _default() { | ||
var _this2 = this; | ||
validate(value, path) { | ||
invalid(list.includes(value), options.message ?? `String must be one of: ${list.join(', ')}`, path, value); | ||
} | ||
var struct = {}; | ||
Object.keys(this.contents).forEach(function (baseKey) { | ||
var key = baseKey; | ||
struct[key] = _this2.contents[key].default(); | ||
}); | ||
return struct; | ||
}; | ||
} | ||
/** | ||
* Require field value to be all lower case. | ||
*/ | ||
_proto.exact = function exact() { | ||
this.isExact = true; | ||
return this; | ||
}; | ||
_proto.doRun = function doRun(value, path) { | ||
var _this$schema, | ||
_this$schema2, | ||
_this3 = this; | ||
function lowerCase(state, options = {}) { | ||
return { | ||
skipIfNull: true, | ||
if ("production" !== process.env.NODE_ENV && value) { | ||
this.invariant(isObject(value), 'Value passed to shape must be an object.', path); | ||
validate(value, path) { | ||
invalid(value === value.toLocaleLowerCase(), options.message ?? 'String must be lower cased.', path, value); | ||
} | ||
var unknownFields = _extends({}, value); | ||
}; | ||
} | ||
/** | ||
* Require field value to be all upper case. | ||
*/ | ||
var struct = _extends({}, value); | ||
var oldPath = (_this$schema = this.schema) == null ? void 0 : _this$schema.parentPath; | ||
var oldStruct = (_this$schema2 = this.schema) == null ? void 0 : _this$schema2.parentStruct; | ||
this.schema.parentPath = path; | ||
this.schema.parentStruct = struct; | ||
Object.keys(this.contents).forEach(function (baseKey) { | ||
var key = baseKey; | ||
var content = _this3.contents[key]; | ||
struct[key] = content.run(value == null ? void 0 : value[key], path + "." + key, _this3.schema); | ||
delete unknownFields[key]; | ||
}); | ||
function upperCase(state, options = {}) { | ||
return { | ||
skipIfNull: true, | ||
if (this.isExact) { | ||
if ("production" !== process.env.NODE_ENV) { | ||
logUnknown(unknownFields, path); | ||
} | ||
} else { | ||
Object.assign(struct, unknownFields); | ||
validate(value, path) { | ||
invalid(value === value.toLocaleUpperCase(), options.message ?? 'String must be upper cased.', path, value); | ||
} | ||
this.schema.parentPath = oldPath; | ||
this.schema.parentStruct = oldStruct; | ||
return struct; | ||
}; | ||
return ShapePredicate; | ||
}(Predicate); | ||
function shape(contents) { | ||
return new ShapePredicate(contents); | ||
} | ||
/** | ||
* Require field array to be of a specific size. | ||
*/ | ||
function isString(value) { | ||
return typeof value === 'string' && value !== ''; | ||
} | ||
var StringPredicate = function (_CollectionPredicate) { | ||
_inheritsLoose(StringPredicate, _CollectionPredicate); | ||
function StringPredicate(defaultValue) { | ||
return _CollectionPredicate.call(this, 'string', defaultValue) || this; | ||
function sizeOf(state, size, options = {}) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(typeof size === 'number' && size > 0, 'Size requires a non-zero positive number.'); | ||
} | ||
var _proto = StringPredicate.prototype; | ||
return { | ||
skipIfNull: true, | ||
_proto.camelCase = function camelCase() { | ||
return this.match(/^[a-z][0-9A-Za-z]+$/, 'String must be in camel case.'); | ||
}; | ||
validate(value, path) { | ||
invalid(value.length === size, options.message ?? `String length must be ${size}.`, path, value); | ||
} | ||
_proto.cast = function cast(value) { | ||
return value === undefined ? '' : String(value); | ||
}; | ||
} | ||
_proto.contains = function contains(token, index) { | ||
var _this = this; | ||
const stringCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
contains: contains, | ||
match: match, | ||
camelCase: camelCase, | ||
kebabCase: kebabCase, | ||
pascalCase: pascalCase, | ||
snakeCase: snakeCase, | ||
notEmpty: notEmpty, | ||
oneOf: oneOf, | ||
lowerCase: lowerCase, | ||
upperCase: upperCase, | ||
sizeOf: sizeOf | ||
}); | ||
/** | ||
* Require field array items to be of a specific schema type. | ||
* Will rebuild the array and type cast values. | ||
*/ | ||
if (index === void 0) { | ||
index = 0; | ||
} | ||
function of$1(state, itemsSchemas) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(Array.isArray(itemsSchemas) && itemsSchemas.length > 0 && itemsSchemas.every(isSchema), 'A non-empty array of schemas are required for a tuple.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(isString(token), 'Contains requires a non-empty token.'); | ||
this.addCheck(function (path, value) { | ||
if (_this.isOptionalDefault(value)) { | ||
return; | ||
} | ||
state.type = `tuple<${itemsSchemas.map(item => item.type()).join(', ')}>`; | ||
return { | ||
skipIfNull: true, | ||
_this.invariant(value.includes(token, index), "String does not include \"" + token + "\".", path); | ||
}); | ||
validate(value, path, validateOptions) { | ||
invalid(Array.isArray(value) && value.length <= itemsSchemas.length, `Value must be a tuple with ${itemsSchemas.length} items.`, path, value); | ||
return itemsSchemas.map((item, i) => item.validate(value[i], `${path}[${i}]`, validateOptions)); | ||
} | ||
return this; | ||
}; | ||
} | ||
_proto.kebabCase = function kebabCase() { | ||
return this.match(/^[a-z][\x2D0-9a-z]+$/, 'String must be in kebab case.'); | ||
}; | ||
const tupleCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
of: of$1 | ||
}); | ||
_proto.lowerCase = function lowerCase() { | ||
var _this2 = this; | ||
function typeOf(value) { | ||
if (Array.isArray(value)) { | ||
return 'array/tuple'; | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
_this2.invariant(value === value.toLocaleLowerCase(), 'String must be lower cased.', path); | ||
}); | ||
} | ||
if (isObject(value)) { | ||
return value.constructor === Object ? 'object/shape' : 'class'; | ||
} | ||
return this; | ||
}; | ||
return typeof value; | ||
} | ||
/** | ||
* Require field value to be one of a specific schema type. | ||
*/ | ||
_proto.match = function match(pattern, message) { | ||
var _this3 = this; | ||
if (message === void 0) { | ||
message = ''; | ||
} | ||
function of(state, schemas) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(Array.isArray(schemas) && schemas.length > 0 && schemas.every(isSchema), 'A non-empty array of schemas are required for a union.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(pattern instanceof RegExp, 'Match requires a regular expression to match against.'); | ||
this.addCheck(function (path, value) { | ||
if (_this3.isOptionalDefault(value)) { | ||
return; | ||
state.type = schemas.map(item => item.type()).join(' | '); | ||
return { | ||
skipIfNull: true, | ||
validate(value, path, validateOptions) { | ||
let nextValue = value; | ||
const allowedValues = schemas.map(schema => schema.type()).join(', '); | ||
const valueType = typeOf(value); | ||
const collectionError = new ValidationError(`Received ${valueType} with the following failures:`, path, value); | ||
const passed = schemas.some(schema => { | ||
const schemaType = schema.schema(); | ||
if (schemaType === 'union') { | ||
invalid(false, 'Nested unions are not supported.', path); | ||
} | ||
_this3.invariant(!!value.match(pattern), (message || 'String does not match.') + " (pattern \"" + pattern.source + "\")", path); | ||
return tryAndCollect(() => { | ||
if (valueType === schemaType || valueType === 'object/shape' && schemaType === 'object' || valueType === 'object/shape' && schemaType === 'shape' || valueType === 'array/tuple' && schemaType === 'array' || valueType === 'array/tuple' && schemaType === 'tuple' || schemaType === 'custom') { | ||
// Dont pass path so its not included in the error message | ||
nextValue = schema.validate(value, '', validateOptions); | ||
return true; | ||
} | ||
return false; | ||
}, collectionError, validateOptions.collectErrors); | ||
}); | ||
if (!passed) { | ||
if (collectionError.errors.length > 0) { | ||
throw collectionError; | ||
} else { | ||
invalid(false, `Value must be one of: ${allowedValues}.`, path, value); | ||
} | ||
} | ||
return nextValue; | ||
} | ||
return this; | ||
}; | ||
} | ||
_proto.notEmpty = function notEmpty() { | ||
var _this4 = this; | ||
const unionCriteria = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
of: of | ||
}); | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
if (_this4.isNullable && value === null) { | ||
return; | ||
} | ||
function array(defaultValue = []) { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...arrayCriteria | ||
}, | ||
cast: createArray, | ||
defaultValue, | ||
type: 'array' | ||
}, [{ | ||
skipIfNull: true, | ||
_this4.invariant(isString(value), 'String cannot be empty.', path); | ||
}); | ||
validate(value, path) { | ||
invalid(Array.isArray(value), 'Must be an array.', path, value); | ||
} | ||
return this; | ||
}; | ||
}]); | ||
} | ||
_proto.oneOf = function oneOf(list) { | ||
var _this5 = this; | ||
function object(defaultValue) { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...objectCriteria | ||
}, | ||
cast: createObject, | ||
defaultValue: defaultValue ?? {}, | ||
type: 'object' | ||
}, [{ | ||
skipIfNull: true, | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.invariant(Array.isArray(list) && list.length > 0 && list.every(function (item) { | ||
return isString(item); | ||
}), 'One of requires a non-empty array of strings.'); | ||
this.addCheck(function (path, value) { | ||
_this5.invariant(list.includes(value), "String must be one of: " + list.join(', '), path); | ||
}); | ||
validate(value, path) { | ||
invalid(isObject(value), 'Must be a plain object.', path, value); | ||
} | ||
return this; | ||
}; | ||
}]); | ||
} // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
_proto.pascalCase = function pascalCase() { | ||
return this.match(/^[A-Z][0-9A-Za-z]+$/, 'String must be in pascal case.'); | ||
}; | ||
_proto.snakeCase = function snakeCase() { | ||
return this.match(/^[a-z][0-9_a-z]+$/, 'String must be in snake case.'); | ||
}; | ||
function func(defaultValue) { | ||
return createSchema({ | ||
api: { ...commonCriteria | ||
}, | ||
defaultValue, | ||
type: 'function' | ||
}, [{ | ||
skipIfNull: true, | ||
skipIfOptional: true, | ||
_proto.upperCase = function upperCase() { | ||
var _this6 = this; | ||
validate(value, path) { | ||
invalid(typeof value === 'function', 'Must be a function.', path, value); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
this.addCheck(function (path, value) { | ||
_this6.invariant(value === value.toLocaleUpperCase(), 'String must be upper cased.', path); | ||
}); | ||
}]); | ||
} // This is similar to shape, but we want to control the validation | ||
function schema() { | ||
const shape = createSchema({ | ||
api: { ...commonCriteria, | ||
...shapeCriteria | ||
}, | ||
cast: createObject, | ||
type: 'shape' | ||
}, [{ | ||
skipIfNull: true, | ||
validate(value, path) { | ||
invalid(isObject(value), 'Must be a schema.', path, value); | ||
} | ||
return this; | ||
}; | ||
}]); | ||
return shape.of({ | ||
schema: func().notNullable().required(), | ||
type: func().notNullable().required(), | ||
validate: func().notNullable().required() | ||
}); | ||
} | ||
return StringPredicate; | ||
}(CollectionPredicate); | ||
function string(defaultValue) { | ||
return new StringPredicate(defaultValue); | ||
function blueprint(defaultValue) | ||
/* infer */ | ||
{ | ||
return object(defaultValue).of(schema().notNullable()); | ||
} | ||
var TuplePredicate = function (_Predicate) { | ||
_inheritsLoose(TuplePredicate, _Predicate); | ||
function bool(defaultValue = false) { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...booleanCriteria | ||
}, | ||
cast: Boolean, | ||
defaultValue, | ||
type: 'boolean' | ||
}, [{ | ||
skipIfNull: true, | ||
function TuplePredicate(contents) { | ||
var _this; | ||
validate(value, path) { | ||
invalid(typeof value === 'boolean', 'Must be a boolean.', path, value); | ||
} | ||
_this = _Predicate.call(this, 'tuple', []) || this; | ||
_this.contents = void 0; | ||
}]); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
_this.invariant(Array.isArray(contents) && contents.length > 0 && contents.every(function (content) { | ||
return content instanceof Predicate; | ||
}), 'A non-empty array of blueprints are required for a tuple.'); | ||
function custom(validator, defaultValue) { | ||
return createSchema({ | ||
api: { ...commonCriteria | ||
}, | ||
defaultValue, | ||
type: 'custom' | ||
}).custom(validator); | ||
} | ||
function date(defaultValue) { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...dateCriteria | ||
}, | ||
cast: createDate, | ||
defaultValue: defaultValue ?? new Date(), | ||
type: 'date' | ||
}, [{ | ||
skipIfNull: true, | ||
validate(value, path) { | ||
const time = createDate(value); | ||
invalid(isValidDate(time), 'Must be a string, number, or `Date` that resolves to a valid date.', path, value); | ||
return time; | ||
} | ||
_this.contents = contents; | ||
return _this; | ||
} | ||
}]); | ||
} | ||
var _proto = TuplePredicate.prototype; | ||
function instance() { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...classCriteria | ||
}, | ||
defaultValue: null, | ||
type: 'class' | ||
}, [state => ({ | ||
skipIfNull: true, | ||
_proto.default = function _default() { | ||
return this.contents.map(function (content) { | ||
return content.default(); | ||
}); | ||
}; | ||
validate(value, path) { | ||
invalid(isObject(value) && value.constructor !== Object, state.type === 'class' ? 'Must be a class instance.' : `Must be an instance of ${state.type}.`, path, value); | ||
} | ||
_proto.typeAlias = function typeAlias() { | ||
return "tuple<" + this.contents.map(function (item) { | ||
return item.typeAlias(); | ||
}).join(', ') + ">"; | ||
}; | ||
})]).nullable(); | ||
} | ||
_proto.doRun = function doRun(value, path) { | ||
var _this2 = this; | ||
function lazy(factory, defaultValue) { | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(typeof factory === 'function', 'Lazy requires a schema factory function.'); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
if (value) { | ||
this.invariant(Array.isArray(value) && value.length <= this.contents.length, "Value must be a tuple with less than or equal to " + this.contents.length + " items."); | ||
return createSchema({ | ||
api: { ...commonCriteria | ||
}, | ||
defaultValue, | ||
type: 'lazy' | ||
}, [{ | ||
// Avoid recursion by returning early and using the provided default value | ||
skipIfNull: true, | ||
skipIfOptional: true, | ||
validate(value, path, validateOptions) { | ||
const schema = factory(value); | ||
if (process.env.NODE_ENV !== "production") { | ||
invariant(isSchema(schema), 'Factory must return a schema.'); | ||
} | ||
return schema.validate(value, path, validateOptions); | ||
} | ||
var nextValue = value ? [].concat(value) : []; | ||
this.contents.forEach(function (content, i) { | ||
nextValue[i] = content.run(nextValue[i], path + "[" + i + "]", _this2.schema); | ||
}); | ||
return nextValue; | ||
}; | ||
}]); | ||
} | ||
return TuplePredicate; | ||
}(Predicate); | ||
function tuple(contents) { | ||
return new TuplePredicate(contents); | ||
function cast$1(value) { | ||
return value === undefined ? 0 : Number(value); | ||
} | ||
var UnionPredicate = function (_Predicate) { | ||
_inheritsLoose(UnionPredicate, _Predicate); | ||
function number(defaultValue = 0) { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...numberCriteria | ||
}, | ||
cast: cast$1, | ||
defaultValue, | ||
type: 'number' | ||
}, [{ | ||
skipIfNull: true, | ||
function UnionPredicate(contents, defaultValue) { | ||
var _this; | ||
validate(value, path) { | ||
invalid(typeof value === 'number', 'Must be a number.', path, value); | ||
} | ||
_this = _Predicate.call(this, 'union', defaultValue) || this; | ||
_this.contents = []; | ||
}]); | ||
} | ||
if ("production" !== process.env.NODE_ENV) { | ||
_this.invariant(Array.isArray(contents) && contents.length > 0 && contents.every(function (content) { | ||
return content instanceof Predicate; | ||
}), 'A non-empty array of blueprints are required for a union.'); | ||
function regex() | ||
/* infer */ | ||
{ | ||
return instance().of(RegExp); | ||
} | ||
_this.addCheck(_this.checkUnions); | ||
} | ||
function shape(blueprint) { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...shapeCriteria | ||
}, | ||
cast: createObject, | ||
type: 'shape' | ||
}, [{ | ||
skipIfNull: true, | ||
_this.contents = contents; | ||
return _this; | ||
} | ||
validate(value, path) { | ||
if (value === undefined) { | ||
// Will be built from its items | ||
return {}; | ||
} | ||
var _proto = UnionPredicate.prototype; | ||
invalid(isObject(value), 'Must be a shaped object.', path, value); | ||
return value; | ||
} | ||
_proto.typeAlias = function typeAlias() { | ||
return this.contents.map(function (content) { | ||
return content.typeAlias(); | ||
}).join(' | '); | ||
}; | ||
}]).of(blueprint); | ||
} | ||
_proto.checkUnions = function checkUnions(path, value) { | ||
var _this2 = this; | ||
function cast(value) { | ||
return value === undefined ? '' : String(value); | ||
} | ||
var nextValue = value; | ||
function string(defaultValue = '') { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...stringCriteria | ||
}, | ||
cast, | ||
defaultValue, | ||
type: 'string' | ||
}, [{ | ||
skipIfNull: true, | ||
if ("production" !== process.env.NODE_ENV) { | ||
var contents = this.contents; | ||
var keys = contents.map(function (content) { | ||
return content.typeAlias(); | ||
}).join(', '); | ||
var type = typeOf(value); | ||
var errors = new Set(); | ||
var passed = contents.some(function (content) { | ||
if (content.type === 'union') { | ||
_this2.invariant(false, 'Nested unions are not supported.', path); | ||
} | ||
validate(value, path) { | ||
invalid(typeof value === 'string', 'Must be a string.', path, value); | ||
} | ||
try { | ||
if (type === content.type || type === 'object' && content.type === 'shape' || type === 'array' && content.type === 'tuple' || content.type === 'custom') { | ||
content.noErrorPrefix = true; | ||
nextValue = content.run(value, path, _this2.schema); | ||
return true; | ||
} | ||
} catch (error) { | ||
errors.add("\n - " + error.message); | ||
} | ||
}]); | ||
} | ||
return false; | ||
}); | ||
var displayValue = this.extractDisplayValue(value); | ||
var message = contents.length === 1 ? "Received " + displayValue + " but must be: " + keys : "Received " + displayValue + " but must be a union of: " + keys; | ||
function tuple(schemas) { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...tupleCriteria | ||
}, | ||
// @ts-expect-error Ignore this, it's safe | ||
cast: createArray, | ||
type: 'tuple' | ||
}, [{ | ||
skipIfNull: true, | ||
if (!passed && errors.size > 0) { | ||
errors.forEach(function (error) { | ||
message += error; | ||
}); | ||
validate(value, path) { | ||
if (value === undefined) { | ||
// Will be built from its items | ||
return []; | ||
} | ||
this.invariant(passed, message.trim(), path); | ||
invalid(Array.isArray(value), 'Must be a tuple.', path, value); | ||
return value; | ||
} | ||
return nextValue; | ||
}; | ||
}]).of(schemas); | ||
} | ||
return UnionPredicate; | ||
}(Predicate); | ||
function union(contents, defaultValue) { | ||
return new UnionPredicate(contents, defaultValue); | ||
function union(defaultValue) { | ||
return createSchema({ | ||
api: { ...commonCriteria, | ||
...unionCriteria | ||
}, | ||
defaultValue, | ||
type: 'union' | ||
}); | ||
} | ||
/** | ||
* @copyright 2017-2019, Miles Johnson | ||
* @license https://opensource.org/licenses/MIT | ||
*/ | ||
var predicates = { | ||
const index = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
array: array, | ||
@@ -1400,6 +1638,7 @@ blueprint: blueprint, | ||
instance: instance, | ||
lazy: lazy, | ||
number: number, | ||
object: object, | ||
predicate: predicate, | ||
regex: regex, | ||
schema: schema, | ||
shape: shape, | ||
@@ -1409,5 +1648,69 @@ string: string, | ||
union: union | ||
}; | ||
}); | ||
export default optimal; | ||
export { ArrayPredicate, BooleanPredicate, InstancePredicate, NumberPredicate, ObjectPredicate, Predicate, Schema, ShapePredicate, StringPredicate, TuplePredicate, UnionPredicate, array, blueprint, bool, custom, date, func, instance, number, object, predicate, predicates, regex, shape, string, tuple, union }; | ||
function createPredicate(schema) { | ||
return value => { | ||
try { | ||
schema.validate(value); | ||
} catch { | ||
return false; | ||
} | ||
return true; | ||
}; | ||
} | ||
function optimal(blueprint, baseOpts = {}) { | ||
const options = {}; | ||
let schema = shape(blueprint); | ||
function configure(nextOpts) { | ||
if (!isObject(nextOpts)) { | ||
throw new TypeError('Optimal options must be a plain object.'); | ||
} | ||
Object.assign(options, nextOpts); | ||
schema = schema.exact(!options.unknown); | ||
} | ||
configure(baseOpts); | ||
return { | ||
configure, | ||
validate(struct, validateOptions) { | ||
const object = struct; | ||
try { | ||
return schema.validate(struct, options.prefix ?? '', { | ||
collectErrors: true, | ||
...validateOptions, | ||
currentObject: object, | ||
rootObject: object | ||
}); | ||
} catch (error) { | ||
let invalid; | ||
if (error instanceof OptimalError) { | ||
invalid = error; | ||
} else { | ||
invalid = new OptimalError(); | ||
invalid.addError(error); | ||
} | ||
if (options.name) { | ||
invalid.schema = options.name; | ||
} | ||
if (options.file) { | ||
invalid.file = options.file; | ||
} | ||
throw invalid; | ||
} | ||
} | ||
}; | ||
} | ||
export { OptimalError, ValidationError, array, arrayCriteria, blueprint, bool, booleanCriteria, classCriteria, commonCriteria, createPredicate, createSchema, custom, date, dateCriteria, func, instance, lazy, number, numberCriteria, object, objectCriteria, optimal, regex, schema, index as schemas, shape, shapeCriteria, string, stringCriteria, tuple, tupleCriteria, union, unionCriteria }; | ||
//# sourceMappingURL=index.js.map |
101
package.json
{ | ||
"name": "optimal", | ||
"version": "4.3.0", | ||
"description": "A system for building and validating defined object structures.", | ||
"main": "./lib/index.js", | ||
"type": "module", | ||
"version": "5.0.0-alpha.1", | ||
"description": "A system for building and validating defined object structures with schemas.", | ||
"main": "./mjs/index.mjs", | ||
"module": "./esm/index.js", | ||
"types": "./lib/index.d.ts", | ||
"scripts": { | ||
"prepare": "beemo create-config --silent", | ||
"build": "beemo create-config babel --esm --silent && rollup --config && beemo typescript --emitDeclarationOnly", | ||
"coverage": "yarn run jest --coverage", | ||
"eslint": "beemo eslint", | ||
"jest": "beemo jest", | ||
"prettier": "beemo prettier", | ||
"prerelease": "yarn test && yarn run build", | ||
"release": "npx np --yolo --no-yarn", | ||
"pretest": "yarn run type", | ||
"test": "yarn run jest", | ||
"posttest": "yarn run eslint", | ||
"type": "beemo typescript --noEmit" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/milesj/optimal.git" | ||
}, | ||
"types": "./dts/index.d.ts", | ||
"keywords": [ | ||
"opts", | ||
"options", | ||
"schema", | ||
"predicate", | ||
@@ -37,2 +21,7 @@ "validator", | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git@github.com:milesj/optimal.git", | ||
"directory": "optimal" | ||
}, | ||
"author": { | ||
@@ -43,40 +32,44 @@ "name": "Miles Johnson", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/milesj/optimal/issues" | ||
}, | ||
"homepage": "https://github.com/milesj/optimal#readme", | ||
"files": [ | ||
"dts/**/*.d.ts", | ||
"esm/**/*.{js,map}", | ||
"mjs/**/*.{js,map}", | ||
"mjs/**/*.{mjs,map}", | ||
"src/**/*.{ts,tsx,json}" | ||
], | ||
"engines": { | ||
"node": ">=10.10.0" | ||
"node": ">=12.17.0", | ||
"npm": ">=6.13.0" | ||
}, | ||
"funding": { | ||
"type": "ko-fi", | ||
"url": "https://ko-fi.com/milesjohnson" | ||
}, | ||
"packemon": { | ||
"bundle": true, | ||
"format": [ | ||
"mjs", | ||
"esm" | ||
], | ||
"platform": [ | ||
"browser", | ||
"node" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@milesj/build-tools": "^2.17.1", | ||
"@types/node": "^14.14.31", | ||
"conventional-changelog-beemo": "^2.1.0", | ||
"rollup": "^2.39.0", | ||
"rollup-plugin-babel": "^4.4.0", | ||
"rollup-plugin-node-resolve": "^5.2.0" | ||
"@jest/globals": "*" | ||
}, | ||
"beemo": { | ||
"module": "@milesj/build-tools", | ||
"drivers": [ | ||
"babel", | ||
"eslint", | ||
"jest", | ||
"prettier", | ||
"typescript" | ||
], | ||
"eslint": { | ||
"rules": { | ||
"default-param-last": "off", | ||
"no-param-reassign": "off" | ||
} | ||
"exports": { | ||
"./package.json": "./package.json", | ||
".": { | ||
"browser": { | ||
"import": "./esm/index.js", | ||
"module": "./esm/index.js" | ||
}, | ||
"node": { | ||
"import": "./mjs/index.mjs" | ||
}, | ||
"types": "./dts/index.d.ts" | ||
} | ||
}, | ||
"browserslist": [ | ||
"ie 11" | ||
], | ||
"funding": { | ||
"type": "ko-fi", | ||
"url": "https://ko-fi.com/milesjohnson" | ||
} | ||
} |
@@ -26,4 +26,4 @@ # Optimal | ||
name: string().notEmpty(), | ||
include: array(string()), | ||
exclude: array(string()), | ||
include: array().of(string()), | ||
exclude: array().of(string()), | ||
maxSize: number(10000).gte(0), | ||
@@ -44,4 +44,4 @@ }, | ||
- Node 10 (server) | ||
- IE 11+ (browser) | ||
- Node 12.17+ | ||
- Edge / Modern browsers | ||
@@ -48,0 +48,0 @@ ## Installation |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
261888
1
81
5351
Yes
1
2
1