import type { ParseContext, SchemaNode } from "../types.js"; import { BaseSchema } from "./base.js"; /** Convert a union of types to an intersection. */ type UnionToIntersection = ( U extends any ? (x: U) => void : never ) extends (x: infer I) => void ? I : never; /** Flatten an intersection into a clean single-level type. */ type Prettify = { [K in keyof T]: T[K] } & {}; export class IntersectionSchema< T extends BaseSchema[] = BaseSchema[], > extends BaseSchema< unknown, Prettify> > { private _schemas: T; constructor(schemas: [...T]) { super(); this._schemas = schemas as T; } _validate(input: unknown, ctx: ParseContext): unknown { let result: unknown = input; let anyFailed = false; for (const schema of this._schemas) { const innerCtx: ParseContext = { path: [...ctx.path], issues: [], // Propagate recursion depth and circular-reference tracking so the // depth guard is not reset (and bypassed) at each intersection member. definitions: ctx.definitions, seen: ctx.seen, depth: ctx.depth, sensitiveMode: ctx.sensitiveMode, sensitiveTransform: ctx.sensitiveTransform, sensitiveCache: ctx.sensitiveCache, }; const validated = schema._runPipeline(input, innerCtx); if (innerCtx.issues.length > 0) { ctx.issues.push(...innerCtx.issues); anyFailed = true; } else { // Merge object results if ( typeof result === "object" && result !== null && typeof validated === "object" && validated !== null && !Array.isArray(result) && !Array.isArray(validated) ) { result = { ...(result as Record), ...(validated as Record), }; } else { result = validated; } } } if (anyFailed) { return undefined; } return result; } _children(): BaseSchema[] { return this._schemas; } _toNode(): SchemaNode { const node = { kind: "intersection" as const, allOf: this._schemas.map((s) => s._toNode()), }; this._addDefault(node as unknown as SchemaNode); return node as unknown as SchemaNode; } }