@metamask/superstruct
Version:
A simple and composable way to validate data in JavaScript (and TypeScript).
1 lines • 10.6 kB
Source Map (JSON)
{"version":3,"file":"refinements.mjs","sourceRoot":"","sources":["../../src/structs/refinements.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Refiner } from '../struct.js';\nimport { Struct } from '../struct.js';\nimport { toFailures } from '../utils.js';\n\n/**\n * Ensure that a string, array, map, or set is empty.\n *\n * @param struct - The struct to augment.\n * @returns A new struct that will only accept empty values.\n */\nexport function empty<\n Type extends string | any[] | Map<any, any> | Set<any>,\n Schema,\n>(struct: Struct<Type, Schema>): Struct<Type, Schema> {\n return refine(struct, 'empty', (value) => {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const size = getSize(value);\n return (\n size === 0 ||\n `Expected an empty ${struct.type} but received one with a size of \\`${size}\\``\n );\n });\n}\n\n/**\n * Get the size of a string, array, map, or set.\n *\n * @param value - The value to measure.\n * @returns The size of the value.\n */\nfunction getSize(value: string | any[] | Map<any, any> | Set<any>): number {\n if (value instanceof Map || value instanceof Set) {\n return value.size;\n }\n\n return value.length;\n}\n\n/**\n * Ensure that a number or date is below a threshold.\n *\n * @param struct - The struct to augment.\n * @param threshold - The maximum value that the input can be.\n * @param options - An optional options object.\n * @param options.exclusive - When `true`, the input must be strictly less than\n * the threshold. When `false`, the input must be less than or equal to the\n * threshold.\n * @returns A new struct that will only accept values below the threshold.\n */\nexport function max<Type extends number | Date, Schema>(\n struct: Struct<Type, Schema>,\n threshold: Type,\n options: {\n exclusive?: boolean | undefined;\n } = {},\n): Struct<Type, Schema> {\n const { exclusive } = options;\n return refine(struct, 'max', (value) => {\n return exclusive\n ? value < threshold\n : value <= threshold ||\n `Expected a ${struct.type} less than ${\n exclusive ? '' : 'or equal to '\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n }${threshold} but received \\`${value}\\``;\n });\n}\n\n/**\n * Ensure that a number or date is above a threshold.\n *\n * @param struct - The struct to augment.\n * @param threshold - The minimum value that the input can be.\n * @param options - An optional options object.\n * @param options.exclusive - When `true`, the input must be strictly greater\n * than the threshold. When `false`, the input must be greater than or equal to\n * the threshold.\n * @returns A new struct that will only accept values above the threshold.\n */\nexport function min<Type extends number | Date, Schema>(\n struct: Struct<Type, Schema>,\n threshold: Type,\n options: {\n exclusive?: boolean | undefined;\n } = {},\n): Struct<Type, Schema> {\n const { exclusive } = options;\n return refine(struct, 'min', (value) => {\n return exclusive\n ? value > threshold\n : value >= threshold ||\n `Expected a ${struct.type} greater than ${\n exclusive ? '' : 'or equal to '\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n }${threshold} but received \\`${value}\\``;\n });\n}\n\n/**\n * Ensure that a string, array, map or set is not empty.\n *\n * @param struct - The struct to augment.\n * @returns A new struct that will only accept non-empty values.\n */\nexport function nonempty<\n Type extends string | any[] | Map<any, any> | Set<any>,\n Schema,\n>(struct: Struct<Type, Schema>): Struct<Type, Schema> {\n return refine(struct, 'nonempty', (value) => {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const size = getSize(value);\n return (\n size > 0 || `Expected a nonempty ${struct.type} but received an empty one`\n );\n });\n}\n\n/**\n * Ensure that a string matches a regular expression.\n *\n * @param struct - The struct to augment.\n * @param regexp - The regular expression to match against.\n * @returns A new struct that will only accept strings matching the regular\n * expression.\n */\nexport function pattern<Type extends string, Schema>(\n struct: Struct<Type, Schema>,\n regexp: RegExp,\n): Struct<Type, Schema> {\n return refine(struct, 'pattern', (value) => {\n return (\n regexp.test(value) ||\n `Expected a ${struct.type} matching \\`/${regexp.source}/\\` but received \"${value}\"`\n );\n });\n}\n\n/**\n * Ensure that a string, array, number, date, map, or set has a size (or length,\n * or time) between `min` and `max`.\n *\n * @param struct - The struct to augment.\n * @param minimum - The minimum size that the input can be.\n * @param maximum - The maximum size that the input can be.\n * @returns A new struct that will only accept values within the given size\n * range.\n */\nexport function size<\n Type extends string | number | Date | any[] | Map<any, any> | Set<any>,\n Schema,\n>(\n struct: Struct<Type, Schema>,\n minimum: number,\n maximum: number = minimum,\n): Struct<Type, Schema> {\n const expected = `Expected a ${struct.type}`;\n const of =\n minimum === maximum\n ? `of \\`${minimum}\\``\n : `between \\`${minimum}\\` and \\`${maximum}\\``;\n\n return refine(struct, 'size', (value) => {\n if (typeof value === 'number' || value instanceof Date) {\n return (\n (minimum <= value && value <= maximum) ||\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `${expected} ${of} but received \\`${value}\\``\n );\n } else if (value instanceof Map || value instanceof Set) {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const { size } = value;\n return (\n (minimum <= size && size <= maximum) ||\n `${expected} with a size ${of} but received one with a size of \\`${size}\\``\n );\n }\n\n const { length } = value;\n return (\n (minimum <= length && length <= maximum) ||\n `${expected} with a length ${of} but received one with a length of \\`${length}\\``\n );\n });\n}\n\n/**\n * Augment a `Struct` to add an additional refinement to the validation.\n *\n * The refiner function is guaranteed to receive a value of the struct's type,\n * because the struct's existing validation will already have passed. This\n * allows you to layer additional validation on top of existing structs.\n *\n * @param struct - The struct to augment.\n * @param name - The name of the refinement.\n * @param refiner - The refiner function.\n * @returns A new struct that will run the refiner function after the existing\n * validation.\n */\nexport function refine<Type, Schema>(\n struct: Struct<Type, Schema>,\n name: string,\n refiner: Refiner<Type>,\n): Struct<Type, Schema> {\n return new Struct({\n ...struct,\n *refiner(value, ctx) {\n yield* struct.refiner(value, ctx);\n const result = refiner(value, ctx);\n const failures = toFailures(result, ctx, struct, value);\n\n for (const failure of failures) {\n yield { ...failure, refinement: name };\n }\n },\n });\n}\n"]}