{"version":3,"file":"struct.mjs","sourceRoot":"","sources":["../src/struct.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Failure } from './error.js';\nimport { StructError } from './error.js';\nimport type { StructSchema } from './utils.js';\nimport { isObject, toFailures, shiftIterator, run } from './utils.js';\n\ntype StructParams<Type, Schema> = {\n  type: string;\n  schema: Schema;\n  coercer?: Coercer | undefined;\n  validator?: Validator | undefined;\n  refiner?: Refiner<Type> | undefined;\n  entries?: Struct<Type, Schema>['entries'] | undefined;\n};\n\n/**\n * `Struct` objects encapsulate the validation logic for a specific type of\n * values. Once constructed, you use the `assert`, `is` or `validate` helpers to\n * validate unknown input data against the struct.\n */\nexport class Struct<Type = unknown, Schema = unknown> {\n  // eslint-disable-next-line @typescript-eslint/naming-convention\n  readonly TYPE!: Type;\n\n  type: string;\n\n  schema: Schema;\n\n  coercer: (value: unknown, context: Context) => unknown;\n\n  validator: (value: unknown, context: Context) => Iterable<Failure>;\n\n  refiner: (value: Type, context: Context) => Iterable<Failure>;\n\n  entries: (\n    value: unknown,\n    context: Context,\n  ) => Iterable<[string | number, unknown, Struct<any> | Struct<never>]>;\n\n  constructor(props: StructParams<Type, Schema>) {\n    const {\n      type,\n      schema,\n      validator,\n      refiner,\n      coercer = (value: unknown) => value,\n      entries = function* () {\n        /* noop */\n      },\n    } = props;\n\n    this.type = type;\n    this.schema = schema;\n    this.entries = entries;\n    this.coercer = coercer;\n\n    if (validator) {\n      this.validator = (value, context) => {\n        const result = validator(value, context);\n        return toFailures(result, context, this, value);\n      };\n    } else {\n      this.validator = () => [];\n    }\n\n    if (refiner) {\n      this.refiner = (value, context) => {\n        const result = refiner(value, context);\n        return toFailures(result, context, this, value);\n      };\n    } else {\n      this.refiner = () => [];\n    }\n  }\n\n  /**\n   * Assert that a value passes the struct's validation, throwing if it doesn't.\n   */\n\n  assert(value: unknown, message?: string): asserts value is Type {\n    return assert(value, this, message);\n  }\n\n  /**\n   * Create a value with the struct's coercion logic, then validate it.\n   */\n\n  create(value: unknown, message?: string): Type {\n    return create(value, this, message);\n  }\n\n  /**\n   * Check if a value passes the struct's validation.\n   */\n\n  is(value: unknown): value is Type {\n    return is(value, this);\n  }\n\n  /**\n   * Mask a value, coercing and validating it, but returning only the subset of\n   * properties defined by the struct's schema.\n   */\n\n  mask(value: unknown, message?: string): Type {\n    return mask(value, this, message);\n  }\n\n  /**\n   * Validate a value with the struct's validation logic, returning a tuple\n   * representing the result.\n   *\n   * You may optionally pass `true` for the `withCoercion` argument to coerce\n   * the value before attempting to validate it. If you do, the result will\n   * contain the coerced result when successful.\n   */\n\n  validate(\n    value: unknown,\n    options: {\n      coerce?: boolean;\n      message?: string;\n    } = {},\n  ): [StructError, undefined] | [undefined, Type] {\n    return validate(value, this, options);\n  }\n}\n\n// String instead of a Symbol in case of multiple different versions of this library.\nconst ExactOptionalBrand = 'EXACT_OPTIONAL';\n\n/**\n * An `ExactOptionalStruct` is a `Struct` that is used to create exactly optional\n * properties of `object()` structs.\n */\nexport class ExactOptionalStruct<\n  Type = unknown,\n  Schema = unknown,\n> extends Struct<Type, Schema> {\n  // ESLint wants us to make this #-private, but we need it to be accessible by\n  // other versions of this library at runtime. If it were #-private, the\n  // implementation would break if multiple instances of this library were\n  // loaded at runtime.\n  // eslint-disable-next-line no-restricted-syntax\n  readonly brand: typeof ExactOptionalBrand;\n\n  constructor(props: StructParams<Type, Schema>) {\n    super({\n      ...props,\n      type: `exact optional ${props.type}`,\n    });\n    this.brand = ExactOptionalBrand;\n  }\n\n  static isExactOptional(value: unknown): value is ExactOptionalStruct {\n    return (\n      isObject(value) && 'brand' in value && value.brand === ExactOptionalBrand\n    );\n  }\n}\n\n/**\n * Assert that a value passes a struct, throwing if it doesn't.\n *\n * @param value - The value to validate.\n * @param struct - The struct to validate against.\n * @param message - An optional message to include in the error.\n */\nexport function assert<Type, Schema>(\n  value: unknown,\n  struct: Struct<Type, Schema>,\n  message?: string,\n): asserts value is Type {\n  const result = validate(value, struct, { message });\n\n  if (result[0]) {\n    throw result[0];\n  }\n}\n\n/**\n * Create a value with the coercion logic of struct and validate it.\n *\n * @param value - The value to coerce and validate.\n * @param struct - The struct to validate against.\n * @param message - An optional message to include in the error.\n * @returns The coerced and validated value.\n */\nexport function create<Type, Schema>(\n  value: unknown,\n  struct: Struct<Type, Schema>,\n  message?: string,\n): Type {\n  const result = validate(value, struct, { coerce: true, message });\n\n  if (result[0]) {\n    throw result[0];\n  } else {\n    return result[1];\n  }\n}\n\n/**\n * Mask a value, returning only the subset of properties defined by a struct.\n *\n * @param value - The value to mask.\n * @param struct - The struct to mask against.\n * @param message - An optional message to include in the error.\n * @returns The masked value.\n */\nexport function mask<Type, Schema>(\n  value: unknown,\n  struct: Struct<Type, Schema>,\n  message?: string,\n): Type {\n  const result = validate(value, struct, { coerce: true, mask: true, message });\n\n  if (result[0]) {\n    throw result[0];\n  } else {\n    return result[1];\n  }\n}\n\n/**\n * Check if a value passes a struct.\n *\n * @param value - The value to validate.\n * @param struct - The struct to validate against.\n * @returns `true` if the value passes the struct, `false` otherwise.\n */\nexport function is<Type, Schema>(\n  value: unknown,\n  struct: Struct<Type, Schema>,\n): value is Type {\n  const result = validate(value, struct);\n  return !result[0];\n}\n\n/**\n * Validate a value against a struct, returning an error if invalid, or the\n * value (with potential coercion) if valid.\n *\n * @param value - The value to validate.\n * @param struct - The struct to validate against.\n * @param options - Optional settings.\n * @param options.coerce - Whether to coerce the value before validating it.\n * @param options.mask - Whether to mask the value before validating it.\n * @param options.message - An optional message to include in the error.\n * @returns A tuple containing the error (if invalid) and the validated value.\n */\nexport function validate<Type, Schema>(\n  value: unknown,\n  struct: Struct<Type, Schema>,\n  options: {\n    coerce?: boolean | undefined;\n    mask?: boolean | undefined;\n    message?: string | undefined;\n  } = {},\n): [StructError, undefined] | [undefined, Type] {\n  const tuples = run(value, struct, options);\n  const tuple = shiftIterator(tuples) as [\n    Failure | undefined,\n    Type | undefined,\n  ];\n\n  if (tuple[0]) {\n    const error = new StructError(tuple[0], function* () {\n      for (const innerTuple of tuples) {\n        if (innerTuple[0]) {\n          yield innerTuple[0];\n        }\n      }\n    });\n\n    return [error, undefined];\n  }\n\n  const validatedValue = tuple[1] as Type;\n  return [undefined, validatedValue];\n}\n\n/**\n * A `Context` contains information about the current location of the\n * validation inside the initial input value.\n */\n\nexport type Context = {\n  branch: any[];\n  path: any[];\n};\n\n/**\n * A type utility to extract the type from a `Struct` class.\n */\n\nexport type Infer<StructType extends Struct<any, any>> = StructType['TYPE'];\n\n/**\n * A type utility to describe that a struct represents a TypeScript type.\n */\n\nexport type Describe<Type> = Struct<Type, StructSchema<Type>>;\n\n/**\n * A `Result` is returned from validation functions.\n */\n\nexport type Result =\n  | boolean\n  | string\n  | Partial<Failure>\n  | Iterable<boolean | string | Partial<Failure>>;\n\n/**\n * A `Coercer` takes an unknown value and optionally coerces it.\n */\n\nexport type Coercer<Type = unknown> = (\n  value: Type,\n  context: Context,\n) => unknown;\n\n/**\n * A `Validator` takes an unknown value and validates it.\n */\n\nexport type Validator = (value: unknown, context: Context) => Result;\n\n/**\n * A `Refiner` takes a value of a known type and validates it against a further\n * constraint.\n */\n\nexport type Refiner<Type> = (value: Type, context: Context) => Result;\n"]}