@metamask/superstruct
Version:
A simple and composable way to validate data in JavaScript (and TypeScript).
1 lines • 13.9 kB
Source Map (JSON)
{"version":3,"file":"utilities.cjs","sourceRoot":"","sources":["../../src/structs/utilities.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context, Validator } from '../struct.js';\nimport { Struct } from '../struct.js';\nimport type {\n Assign,\n ObjectSchema,\n ObjectType,\n PartialObjectSchema,\n} from '../utils.js';\nimport { object, optional, type } from './types.js';\n\n/**\n * Create a new struct that combines the properties from multiple object or type\n * structs. Its return type will match the first parameter's type.\n *\n * Like JavaScript's `Object.assign` utility.\n *\n * @param First - The first struct to combine.\n * @param Second - The second struct to combine.\n * @returns A new struct that combines the properties of the input structs.\n */\nexport function assign<First extends ObjectSchema, Second extends ObjectSchema>(\n First: Struct<ObjectType<First>, First>,\n Second: Struct<ObjectType<Second>, Second>,\n): Struct<ObjectType<Assign<First, Second>>, Assign<First, Second>>;\n\n/**\n * Create a new struct that combines the properties from multiple object or type\n * structs. Its return type will match the first parameter's type.\n *\n * @param First - The first struct to combine.\n * @param Second - The second struct to combine.\n * @param Third - The third struct to combine.\n * @returns A new struct that combines the properties of the input structs.\n */\nexport function assign<\n First extends ObjectSchema,\n Second extends ObjectSchema,\n Third extends ObjectSchema,\n>(\n First: Struct<ObjectType<First>, First>,\n Second: Struct<ObjectType<Second>, Second>,\n Third: Struct<ObjectType<Third>, Third>,\n): Struct<\n ObjectType<Assign<Assign<First, Second>, Third>>,\n Assign<Assign<First, Second>, Third>\n>;\n\n/**\n * Create a new struct that combines the properties from multiple object or type\n * structs. Its return type will match the first parameter's type.\n *\n * @param First - The first struct to combine.\n * @param Second - The second struct to combine.\n * @param Third - The third struct to combine.\n * @param Fourth - The fourth struct to combine.\n * @returns A new struct that combines the properties of the input structs.\n */\nexport function assign<\n First extends ObjectSchema,\n Second extends ObjectSchema,\n Third extends ObjectSchema,\n Fourth extends ObjectSchema,\n>(\n First: Struct<ObjectType<First>, First>,\n Second: Struct<ObjectType<Second>, Second>,\n Third: Struct<ObjectType<Third>, Third>,\n Fourth: Struct<ObjectType<Fourth>, Fourth>,\n): Struct<\n ObjectType<Assign<Assign<Assign<First, Second>, Third>, Fourth>>,\n Assign<Assign<Assign<First, Second>, Third>, Fourth>\n>;\n\n/**\n * Create a new struct that combines the properties from multiple object or type\n * structs. Its return type will match the first parameter's type.\n *\n * @param First - The first struct to combine.\n * @param Second - The second struct to combine.\n * @param Third - The third struct to combine.\n * @param Fourth - The fourth struct to combine.\n * @param Fifth - The fifth struct to combine.\n * @returns A new struct that combines the properties of the input structs.\n */\nexport function assign<\n First extends ObjectSchema,\n Second extends ObjectSchema,\n Third extends ObjectSchema,\n Fourth extends ObjectSchema,\n Fifth extends ObjectSchema,\n>(\n First: Struct<ObjectType<First>, First>,\n Second: Struct<ObjectType<Second>, Second>,\n Third: Struct<ObjectType<Third>, Third>,\n Fourth: Struct<ObjectType<Fourth>, Fourth>,\n Fifth: Struct<ObjectType<Fifth>, Fifth>,\n): Struct<\n ObjectType<\n Assign<Assign<Assign<Assign<First, Second>, Third>, Fourth>, Fifth>\n >,\n Assign<Assign<Assign<Assign<First, Second>, Third>, Fourth>, Fifth>\n>;\n\n/**\n * Create a new struct that combines the properties from multiple object or type\n * structs. Its return type will match the first parameter's type.\n *\n * @param Structs - The structs to combine.\n * @returns A new struct that combines the properties of the input structs.\n */\nexport function assign(...Structs: Struct<any>[]): any {\n const isType = Structs[0]?.type === 'type';\n const schemas = Structs.map(({ schema }) => schema);\n const schema = Object.assign({}, ...schemas);\n return isType ? type(schema) : object(schema);\n}\n\n/**\n * Define a new struct type with a custom validation function.\n *\n * @param name - The name of the struct type.\n * @param validator - The validation function.\n * @returns A new struct type.\n */\nexport function define<Type>(\n name: string,\n validator: Validator,\n): Struct<Type, null> {\n return new Struct({ type: name, schema: null, validator });\n}\n\n/**\n * Create a new struct based on an existing struct, but the value is allowed to\n * be `undefined`. `log` will be called if the value is not `undefined`.\n *\n * @param struct - The struct to augment.\n * @param log - The function to call when the value is not `undefined`.\n * @returns A new struct that will only accept `undefined` or values that pass\n * the input struct.\n */\nexport function deprecated<Type>(\n struct: Struct<Type>,\n log: (value: unknown, ctx: Context) => void,\n): Struct<Type> {\n return new Struct({\n ...struct,\n refiner: (value, ctx) => value === undefined || struct.refiner(value, ctx),\n validator(value, ctx) {\n if (value === undefined) {\n return true;\n }\n log(value, ctx);\n return struct.validator(value, ctx);\n },\n });\n}\n\n/**\n * Create a struct with dynamic validation logic.\n *\n * The callback will receive the value currently being validated, and must\n * return a struct object to validate it with. This can be useful to model\n * validation logic that changes based on its input.\n *\n * @param fn - The callback to create the struct.\n * @returns A new struct with dynamic validation logic.\n */\nexport function dynamic<Type>(\n fn: (value: unknown, ctx: Context) => Struct<Type, any>,\n): Struct<Type, null> {\n return new Struct({\n type: 'dynamic',\n schema: null,\n *entries(value, ctx) {\n const struct = fn(value, ctx);\n yield* struct.entries(value, ctx);\n },\n validator(value, ctx) {\n const struct = fn(value, ctx);\n return struct.validator(value, ctx);\n },\n coercer(value, ctx) {\n const struct = fn(value, ctx);\n return struct.coercer(value, ctx);\n },\n refiner(value, ctx) {\n const struct = fn(value, ctx);\n return struct.refiner(value, ctx);\n },\n });\n}\n\n/**\n * Create a struct with lazily evaluated validation logic.\n *\n * The first time validation is run with the struct, the callback will be called\n * and must return a struct object to use. This is useful for cases where you\n * want to have self-referential structs for nested data structures to avoid a\n * circular definition problem.\n *\n * @param fn - The callback to create the struct.\n * @returns A new struct with lazily evaluated validation logic.\n */\nexport function lazy<Type>(fn: () => Struct<Type, any>): Struct<Type, null> {\n let struct: Struct<Type, any> | undefined;\n return new Struct({\n type: 'lazy',\n schema: null,\n *entries(value, ctx) {\n struct ??= fn();\n yield* struct.entries(value, ctx);\n },\n validator(value, ctx) {\n struct ??= fn();\n return struct.validator(value, ctx);\n },\n coercer(value, ctx) {\n struct ??= fn();\n return struct.coercer(value, ctx);\n },\n refiner(value, ctx) {\n struct ??= fn();\n return struct.refiner(value, ctx);\n },\n });\n}\n\n/**\n * Create a new struct based on an existing object struct, but excluding\n * specific properties.\n *\n * Like TypeScript's `Omit` utility.\n *\n * @param struct - The struct to augment.\n * @param keys - The keys to omit.\n * @returns A new struct that will not accept the input keys.\n */\nexport function omit<Schema extends ObjectSchema, Key extends keyof Schema>(\n struct: Struct<ObjectType<Schema>, Schema>,\n keys: Key[],\n): Struct<ObjectType<Omit<Schema, Key>>, Omit<Schema, Key>> {\n const { schema } = struct;\n const subschema: any = { ...schema };\n\n for (const key of keys) {\n delete subschema[key];\n }\n\n switch (struct.type) {\n case 'type':\n return type(subschema as Omit<Schema, Key>);\n default:\n return object(subschema as Omit<Schema, Key>);\n }\n}\n\n/**\n * Create a new struct based on an existing object struct, but with all of its\n * properties allowed to be `undefined`.\n *\n * Like TypeScript's `Partial` utility.\n *\n * @param struct - The struct to augment.\n * @returns A new struct that will accept the input keys as `undefined`.\n */\nexport function partial<Schema extends ObjectSchema>(\n struct: Struct<ObjectType<Schema>, Schema> | Schema,\n): Struct<\n ObjectType<PartialObjectSchema<Schema>>,\n PartialObjectSchema<Schema>\n> {\n const isStruct = struct instanceof Struct;\n const schema: any = isStruct ? { ...struct.schema } : { ...struct };\n\n // eslint-disable-next-line guard-for-in\n for (const key in schema) {\n schema[key] = optional(schema[key]);\n }\n\n if (isStruct && struct.type === 'type') {\n return type(schema) as any;\n }\n\n return object(schema) as any;\n}\n\n/**\n * Create a new struct based on an existing object struct, but only including\n * specific properties.\n *\n * Like TypeScript's `Pick` utility.\n *\n * @param struct - The struct to augment.\n * @param keys - The keys to pick.\n * @returns A new struct that will only accept the input keys.\n */\nexport function pick<Schema extends ObjectSchema, Key extends keyof Schema>(\n struct: Struct<ObjectType<Schema>, Schema>,\n keys: Key[],\n): Struct<ObjectType<Pick<Schema, Key>>, Pick<Schema, Key>> {\n const { schema } = struct;\n const subschema: any = {};\n\n for (const key of keys) {\n subschema[key] = schema[key];\n }\n\n switch (struct.type) {\n case 'type':\n return type(subschema) as any;\n\n default:\n return object(subschema) as any;\n }\n}\n"]}