@metamask/superstruct
Version:
A simple and composable way to validate data in JavaScript (and TypeScript).
168 lines • 6.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.refine = exports.size = exports.pattern = exports.nonempty = exports.min = exports.max = exports.empty = void 0;
const struct_js_1 = require("../struct.cjs");
const utils_js_1 = require("../utils.cjs");
/**
* Ensure that a string, array, map, or set is empty.
*
* @param struct - The struct to augment.
* @returns A new struct that will only accept empty values.
*/
function empty(struct) {
return refine(struct, 'empty', (value) => {
// eslint-disable-next-line @typescript-eslint/no-shadow
const size = getSize(value);
return (size === 0 ||
`Expected an empty ${struct.type} but received one with a size of \`${size}\``);
});
}
exports.empty = empty;
/**
* Get the size of a string, array, map, or set.
*
* @param value - The value to measure.
* @returns The size of the value.
*/
function getSize(value) {
if (value instanceof Map || value instanceof Set) {
return value.size;
}
return value.length;
}
/**
* Ensure that a number or date is below a threshold.
*
* @param struct - The struct to augment.
* @param threshold - The maximum value that the input can be.
* @param options - An optional options object.
* @param options.exclusive - When `true`, the input must be strictly less than
* the threshold. When `false`, the input must be less than or equal to the
* threshold.
* @returns A new struct that will only accept values below the threshold.
*/
function max(struct, threshold, options = {}) {
const { exclusive } = options;
return refine(struct, 'max', (value) => {
return exclusive
? value < threshold
: value <= threshold ||
`Expected a ${struct.type} less than ${exclusive ? '' : 'or equal to '
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
}${threshold} but received \`${value}\``;
});
}
exports.max = max;
/**
* Ensure that a number or date is above a threshold.
*
* @param struct - The struct to augment.
* @param threshold - The minimum value that the input can be.
* @param options - An optional options object.
* @param options.exclusive - When `true`, the input must be strictly greater
* than the threshold. When `false`, the input must be greater than or equal to
* the threshold.
* @returns A new struct that will only accept values above the threshold.
*/
function min(struct, threshold, options = {}) {
const { exclusive } = options;
return refine(struct, 'min', (value) => {
return exclusive
? value > threshold
: value >= threshold ||
`Expected a ${struct.type} greater than ${exclusive ? '' : 'or equal to '
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
}${threshold} but received \`${value}\``;
});
}
exports.min = min;
/**
* Ensure that a string, array, map or set is not empty.
*
* @param struct - The struct to augment.
* @returns A new struct that will only accept non-empty values.
*/
function nonempty(struct) {
return refine(struct, 'nonempty', (value) => {
// eslint-disable-next-line @typescript-eslint/no-shadow
const size = getSize(value);
return (size > 0 || `Expected a nonempty ${struct.type} but received an empty one`);
});
}
exports.nonempty = nonempty;
/**
* Ensure that a string matches a regular expression.
*
* @param struct - The struct to augment.
* @param regexp - The regular expression to match against.
* @returns A new struct that will only accept strings matching the regular
* expression.
*/
function pattern(struct, regexp) {
return refine(struct, 'pattern', (value) => {
return (regexp.test(value) ||
`Expected a ${struct.type} matching \`/${regexp.source}/\` but received "${value}"`);
});
}
exports.pattern = pattern;
/**
* Ensure that a string, array, number, date, map, or set has a size (or length,
* or time) between `min` and `max`.
*
* @param struct - The struct to augment.
* @param minimum - The minimum size that the input can be.
* @param maximum - The maximum size that the input can be.
* @returns A new struct that will only accept values within the given size
* range.
*/
function size(struct, minimum, maximum = minimum) {
const expected = `Expected a ${struct.type}`;
const of = minimum === maximum
? `of \`${minimum}\``
: `between \`${minimum}\` and \`${maximum}\``;
return refine(struct, 'size', (value) => {
if (typeof value === 'number' || value instanceof Date) {
return ((minimum <= value && value <= maximum) ||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`${expected} ${of} but received \`${value}\``);
}
else if (value instanceof Map || value instanceof Set) {
// eslint-disable-next-line @typescript-eslint/no-shadow
const { size } = value;
return ((minimum <= size && size <= maximum) ||
`${expected} with a size ${of} but received one with a size of \`${size}\``);
}
const { length } = value;
return ((minimum <= length && length <= maximum) ||
`${expected} with a length ${of} but received one with a length of \`${length}\``);
});
}
exports.size = size;
/**
* Augment a `Struct` to add an additional refinement to the validation.
*
* The refiner function is guaranteed to receive a value of the struct's type,
* because the struct's existing validation will already have passed. This
* allows you to layer additional validation on top of existing structs.
*
* @param struct - The struct to augment.
* @param name - The name of the refinement.
* @param refiner - The refiner function.
* @returns A new struct that will run the refiner function after the existing
* validation.
*/
function refine(struct, name, refiner) {
return new struct_js_1.Struct({
...struct,
*refiner(value, ctx) {
yield* struct.refiner(value, ctx);
const result = refiner(value, ctx);
const failures = (0, utils_js_1.toFailures)(result, ctx, struct, value);
for (const failure of failures) {
yield { ...failure, refinement: name };
}
},
});
}
exports.refine = refine;
//# sourceMappingURL=refinements.cjs.map