shelving
Version:
Toolkit for using data in JavaScript.
58 lines (57 loc) • 2.48 kB
JavaScript
import { ValueFeedback } from "../feedback/Feedback.js";
import { getUniqueArray, isArray } from "../util/array.js";
import { validateArray } from "../util/validate.js";
import { Schema } from "./Schema.js";
/**
* Define a valid array.
*
* Validates arrays and ensures the array's items match a specified format.
* Only returns a new instance of the object if it changes (for immutability).
*
* Schema options:
* - `value` The default value
* - `length` The exact array length required
* - `min` The minimum array length required
* - `max` The maximum array length required
* - `values` A schema all the array items in the value must conform to
*
* @example
* const schema = new ArraySchema({ min: 1, max: 2, default: [10,11,12], required: true });
* schema.validate([1,2,3], schema); // Returns [1,2,3]
* schema.validate(undefined, schema); // Returns [10,11,12] (due to value)
* schema.validate([4,5,6,7], schema); // Returns [4,5,6] (due to max)
* schema.validate(9999, schema); // Throws Invalid('Must be array')
* schema.validate([], schema); // Throws Required
* schema.validate([1,2], schema); // Throws Invalid('Needs at least 3 items')
*
* @example
* const schema = new ArraySchema({ schema: Array });
* schema.validate(["a", "a"], schema); // Returns ["a", "a"]
* schema.validate(["a", null], schema); // Throws Invalids({ "1": Invalid('Must be a string') });
*/
export class ArraySchema extends Schema {
items;
unique;
min;
max;
constructor({ items, unique = false, min = 0, max = Number.POSITIVE_INFINITY, title = "Items", value = [], ...options }) {
super({ title, value, ...options });
this.items = items;
this.unique = unique;
this.min = min;
this.max = max;
}
validate(unsafeValue = this.value) {
if (!isArray(unsafeValue))
throw new ValueFeedback("Must be array", unsafeValue);
const validArray = validateArray(unsafeValue, this.items);
const uniqueArray = this.unique ? getUniqueArray(validArray) : validArray;
if (uniqueArray.length < this.min)
throw new ValueFeedback(uniqueArray.length ? `Minimum ${this.min} items` : "Required", uniqueArray);
if (uniqueArray.length > this.max)
throw new ValueFeedback(`Maximum ${this.max} items`, uniqueArray);
return uniqueArray;
}
}
/** Valid array with specifed items. */
export const ARRAY = (items) => new ArraySchema({ items });