import { V as ValidationError, P as PathSegment } from './errors-BahYESV_.js'; import { S as SchemaOrBoolean } from './types-Dzi0PpYX.js'; import { D as Dialect, C as CustomKeywordValidator, R as RefResolver, a as RegexCompiler } from './runtime-BoYh8w5o.js'; /** * Result of a default-mode `validate()` call: a flat list of leaf * errors under `errors`. This is the v3 default (`output: "flat"`), * shaped to match ajv's zero-config result. Every failing leaf keyword * (`type`, `required`, `minimum`, …) is its own record, plus a childless * marker leaf for each failed composition keyword (`anyOf` / `oneOf`); * no `"schema"` branch wrappers. Each record is a {@link ValidationError} * with an empty `children`, so the `@oav/core` renderers consume it * unchanged. For the nested error tree, compile with `output: "tree"` * and see {@link TreeValidationResult}. * * A discriminated union on `valid`: a successful result carries no error * fields; a failing result always carries both `errors` (the flat leaf * list, non-empty) and `truncated`. Narrow on `result.valid` to reach * the error fields. The narrowing also makes a mistaken `result.error` * access (the tree-mode field) a compile error rather than a silent * `undefined`. * * @public */ type ValidationResult = { valid: true; } | { valid: false; /** The flat list of leaf errors. Always non-empty when `!valid`. */ errors: ValidationError[]; /** * `true` when the configured `maxErrors` cap was reached, meaning * the list may be incomplete: validation returns as soon as the * budget drains, without checking the remaining keywords. Under * the v3 default (`maxErrors: 1`) every failing result therefore * reports `truncated: true`. `false` means the cap was never hit * and the list is complete. */ truncated: boolean; }; /** * Result of a tree-mode (`output: "tree"`) `validate()` call: a single * nested {@link ValidationError} tree under `error`, with `"schema"` * branch nodes mirroring the schema's composition structure. The opt-in * counterpart to the flat {@link ValidationResult} default. The HTTP * validator in `@oav/validator` compiles in this mode so it can nest * per-location subtrees (`body`, `query`, …) under one root. * * A discriminated union on `valid`: a successful result carries no error * fields; a failing result always carries both `error` (the tree root) * and `truncated`. * * @public */ type TreeValidationResult = { valid: true; } | { valid: false; /** The root of the nested error tree. Always present when `!valid`. */ error: ValidationError; /** * `true` when at least one error was dropped because the configured * `maxErrors` cap was hit; `false` when the tree is complete. */ truncated: boolean; }; /** * @deprecated Use {@link ValidationResult}. Kept as an alias for one * major; will be removed in v4. * * @public */ type FlatValidationResult = ValidationResult; /** * Compile-time statistics about the generated validator. Exposed so * tests can assert on compiler behavior (e.g. "did subschema inlining * fire?") without grepping the generated source. * * @public */ interface CompileStats { /** * Number of named `validate_N` helper functions emitted. A schema * that gets fully inlined compiles to one function (`validate_0`); * subschemas that stay as functions each add one. */ functionCount: number; /** * `true` iff the compiler actually emitted `evalProps` / `evalItems` * Set machinery anywhere in the generated source. When `false`, the * unevaluated-keys-gating optimization is taking effect: the schema * doesn't use `unevaluatedProperties` / `unevaluatedItems`, so the * compiler suppressed the per-function Set allocation and merge loop. * Surfaced so tests can assert on the optimization directly instead * of grepping the generated JS. */ unevaluatedTrackingEmitted: boolean; /** * `true` iff the generated source references any tree-mode runtime * helper (`createLeafError`, `createBranchError`, `wrapErrors`). In * predicate mode this MUST be `false`: the whole point of the mode * is to avoid allocating an error tree. Surfaced so the predicate- * mode contract can be asserted without grepping the generated JS. */ emittedTreeRuntime: boolean; /** * Warnings produced by {@link CompileOptions.strict}. Empty unless * strict mode is active and found something to flag. Never contains * compile-blocking issues; strict mode only reports; the caller * decides whether to treat any entry as fatal. */ strictIssues: readonly StrictIssue[]; } /** * A single finding from strict-mode schema linting (see * {@link CompileOptions.strict}). * * @public */ interface StrictIssue { /** * - `"partial-feature"`: the schema uses a keyword flagged as * partially-implemented (e.g. `$dynamicRef` without runtime * dynamic-scope rebinding). Compile still succeeds; the emitted * validator's semantics for this keyword may not match the spec. * - `"unknown-keyword"`: the schema declares a key that's not in the * active dialect, not an `x-*` extension, and not a standard * `$`-prefixed metadata key. Likely a typo. * - `"silent-rewrite/ref-siblings-oas30"`: under OAS 3.0 * (`refSuppressesSiblings: true`), a schema with `$ref` plus * sibling keywords other than `description` / `summary`. The * siblings are silently dropped; the validator runs the `$ref` * target only. * - `"silent-rewrite/required-not-in-properties"`: a `required` * array names a key that doesn't appear in the same schema's * `properties`. Almost always a typo. Conservative: skipped on * schemas that mix `required` with `$ref` / `allOf` / `oneOf` / * `anyOf` (the named key could be contributed by a composed * branch). * - `"silent-rewrite/redundant-composition-branches"`: an `oneOf` / * `anyOf` array where two or more branches are structurally * identical after compile-time rewrites (notably the validator's * `format: binary` opaque-body bypass). The compiled validator's * semantics differ from the source spec: identical branches * collapse, changing the match-count behavior. */ code: "partial-feature" | "unknown-keyword" | "silent-rewrite/ref-siblings-oas30" | "silent-rewrite/required-not-in-properties" | "silent-rewrite/redundant-composition-branches"; /** The offending keyword / key name as written in the schema. */ keyword: string; /** Dotted path from the root schema to the subschema holding the key. */ path: string; /** Human-readable explanation. */ message: string; } /** * The function returned by {@link compileSchema}. Call it with any JSON value * to validate against the original schema. An optional `startPath` * is prepended to every error's `path`, useful when the compiled * validator is embedded inside a larger traversal (e.g. the HTTP * validator prepends `["body"]`, `["query", name]`, etc.). The array * is cloned before use and never mutated. * * @public */ type CompiledSchema = { validate: (data: unknown, startPath?: readonly PathSegment[]) => ValidationResult; /** The generated source. Exposed for debugging/snapshot testing only. */ source: string; /** Compile-time stats about the generated validator. */ stats: CompileStats; }; /** * The shape returned by {@link compileSchema} when `output: "tree"` is * set. Same `validate(data, startPath?)` signature as * {@link CompiledSchema}, but returns a {@link TreeValidationResult} (a * single nested error tree) instead of the flat default. See * {@link CompileOptions.output}. Carries the same `source` / `stats` as * {@link CompiledSchema}; only the `validate` return type differs. * * @public */ type CompiledTreeSchema = Omit & { validate: (data: unknown, startPath?: readonly PathSegment[]) => TreeValidationResult; }; /** * The shape returned by {@link compileSchema} when `output: "predicate"` * is set. The validator collects no errors, allocates no tree, and * returns a boolean: a true yes/no predicate. Use when consumers only * need to know whether the value conforms (e.g. routing, gating), not * why it doesn't. Carries the same `source` / `stats` as * {@link CompiledSchema}; only the `validate` return type differs. * * @public */ type CompiledPredicate = Omit & { validate: (data: unknown) => boolean; }; /** * @deprecated Use {@link CompiledSchema}, which returns a flat * {@link ValidationResult} by default. Kept as an alias for one major; * will be removed in v4. * * @public */ type CompiledFlatSchema = CompiledSchema; /** * Options accepted by {@link compileSchema}. * * @remarks * Ordering convention (shared with * {@link @aahoughton/oav!ValidatorOptions}): * * 1. Compile essentials: `dialect`. * 2. Shared extension points: `formats`, `keywords`. * 3. Error-collection policy: `output`, `maxErrors`. * 4. Surface-specific extras last: here, `external`, `refResolver`. * * Options common to both surfaces share names and positions so a * reader of one declaration can predict the other. When adding a new * option, put it in the section that matches its role and use the * same name on the validator side if the concept applies there too. * * @public */ interface CompileOptions { /** * The dialect to compile against. Pick one of the built-ins * (`jsonSchemaDialect`, `openapi31Dialect`, `oas30Dialect`) or * construct a custom {@link Dialect}. */ dialect: Dialect; /** Pre-registered format validators, keyed by format name. */ formats?: Record boolean>; /** * User-registered keywords, keyed by keyword name. Each validator is * invoked whenever its name appears as a property in a schema object. * Custom names must not collide with a keyword already supplied by * the configured dialect. * * @example * ```ts * compileSchema(schema, { * dialect: jsonSchemaDialect, * keywords: { * divisibleBy: (data, schemaValue) => * typeof data !== "number" || data % (schemaValue as number) === 0, * }, * }); * ``` */ keywords?: Record; /** * What `validate()` returns. Selects the result shape: * * - `"flat"` (default): a {@link ValidationResult}: `{ valid }` plus, * on failure, a de-nested `errors` leaf list and `truncated`. Shaped * to match ajv's zero-config output. With the default * `maxErrors: 1`, this is the fast-fail path that hits ajv-class * numbers on the rejection benchmark. * - `"tree"`: a {@link TreeValidationResult}: `{ valid }` plus, on * failure, a single nested {@link ValidationError} tree under `error` * and `truncated`. The rich diagnostic shape; what `@oav/validator` * compiles in so it can nest per-location subtrees. * - `"predicate"`: a {@link CompiledPredicate} whose `validate(data)` * returns a bare `boolean`. No {@link ValidationError} tree is ever * constructed, so consumers who only need a yes/no answer pay nothing * for error-reporting machinery (leaf allocation, path snapshot, * params object, message string). * * Defaults to `"flat"`. The deprecated `flat: true` / `predicate: true` * booleans still work as aliases for `output: "flat"` / `"predicate"`; * supplying both `output` and a conflicting legacy boolean throws. * * `output: "predicate"` is mutually exclusive with a finite * {@link CompileOptions.maxErrors}: a predicate short-circuits at the * first failure, so there is nothing to count. The compiler throws when * both are supplied. */ output?: "flat" | "tree" | "predicate"; /** * Cap on the number of leaf errors collected per `validate()` call. * Defaults to `1` (fast-fail: stop at the first error), matching ajv's * `allErrors: false` zero-config behaviour. Pass * `Number.POSITIVE_INFINITY` to collect everything. * * When set to a finite value: * - Once the cap is reached, `truncated: true` is set on the returned * result and no further errors are reported. * - In flat mode (the default output), reaching the cap returns from * the validator immediately, skipping the remaining keyword checks * entirely; `maxErrors: 1` behaves like ajv's `allErrors: false` * fast-fail. Tree mode keeps walking (to preserve the tree shape) * but stops collecting. * * `maxErrors: 1` is the default (classic fast-fail). To collect every * error, pass `Number.POSITIVE_INFINITY`. * * Must be a positive integer (>= 1) when supplied. A cap of 0 is * effectively predicate mode (no errors collected, validation * collapses to yes/no); for that, prefer `output: "predicate"` * (see {@link CompileOptions.output}) which compiles a fully * specialized function with no error infrastructure at all. * `compileSchema` throws on `maxErrors <= 0`. */ maxErrors?: number; /** * Cap on recursion depth through `$ref` cycles per `validate()` call. * Defaults to uncapped. * * Recursive schemas (a `$ref` that points back at an ancestor, common * for tree / comment structures) validate by recursing on the native * JS call stack. A small but deeply nested payload can exhaust the * stack and throw `RangeError`. Set this to bound the recursion: when * the configured depth is exceeded, validation emits a `depth` error * leaf (mapped to HTTP 400) at the boundary instead of descending * further, so a deep payload fails as invalid rather than crashing. * * The counter increments only at recursive (cycle-closing) `$ref` * boundaries, so it measures how deep the recursive structure nests * and is independent of how the schema was decomposed. Non-recursive * schemas are never instrumented and pay nothing. Legitimate payloads * rarely recurse beyond ten or fifteen levels; a cap of 32 to 64 is * generous for real traffic. * * When unset, codegen is identical to the un-instrumented path (zero * overhead). Must be a positive integer (>= 1); `compileSchema` throws * otherwise. */ maxDepth?: number; /** * Compile-time schema linting. All modes collect to * {@link CompileStats.strictIssues} rather than throwing. * * - `"off"`: silence on everything (pre-v-strict behavior). * - `"warn-partial"` (default): warn on keywords flagged as * partially-implemented (currently `$dynamicRef`; its runtime * dynamic-scope rebinding is not emitted). * - `"strict"`: warn on partial features AND unknown keys (keys not * in the active dialect, not `x-*` extensions, not standard * `$`-prefixed metadata). Catches typos like `minimumx: 5`. */ strict?: "off" | "warn-partial" | "strict"; /** Additional external named schemas that `$ref` can resolve to. */ external?: Map; /** Custom ref resolver; overrides the default (which resolves fragments within the root). */ refResolver?: RefResolver; /** * @deprecated Use `output: "predicate"` (see * {@link CompileOptions.output}). `predicate: true` remains a working * alias for one major and will be removed in v4. Supplying it together * with a conflicting `output` throws. */ predicate?: boolean; /** * @deprecated Use `output: "flat"`. The bare `compileSchema(schema)` * already returns a flat {@link ValidationResult}. `flat: true` remains * a working alias for one major and will be removed in v4. Supplying it * together with a conflicting `output` throws. */ flat?: boolean; /** * Custom compiler for schema `pattern` keywords and the `format: * "regex"` assertion. Defaults to `new RegExp(pattern, "u")` with a * non-`u` fallback. Override to plug in a library like `re2`, wrap * with a complexity check, or reject patterns that fail a * safe-regex analysis. * * JavaScript's built-in `RegExp` has no execution timeout, so a * catastrophic pattern like `(a+)+$` is a denial-of-service vector * against any string the validator checks. Reach for this option * when the spec is attacker-controlled (multi-tenant SaaS, * spec-editing tools, mock-as-a-service). * * The runtime only reads `.test(s: string): boolean` off the * returned object; built-in `RegExp` already satisfies the shape. * Memoization is split by audience: schema `pattern` strings cache * for the validator's lifetime (bounded by spec size), `format: * "regex"` runs the compiler per call (runtime values are not). * See {@link RegexCompiler}. */ regexCompiler?: RegexCompiler; } /** * Return `true` iff `schema` (or any schema reachable from it through * subschema-valued positions) contains the `unevaluatedProperties` or * `unevaluatedItems` keyword. The detector is the gate for the * evaluated-keys-Set machinery: when it's `false`, the compiler emits * a form that skips the per-function Set allocation entirely. * * The walk descends the local subschema positions (the same set * {@link walkSubschemas} uses) and is cycle-safe: a `$ref` value is a * string, so the walk never recurses through one. A schema whose only * `unevaluated*` keyword sits behind a `$ref` is therefore not detected * by this predicate; resolve such refs first if that matters. * * @public */ declare function schemaUsesUnevaluated(schema: SchemaOrBoolean): boolean; /** * Compile a JSON Schema 2020-12 document into an executable validator. * * @param schema - The schema (object or boolean) to compile. * @param options - Vocabularies, formats, external schemas. * @returns A validator function plus the generated source. * * @example * ```ts * const v = compileSchema({ type: "number" }, { dialect: jsonSchemaDialect }); * v.validate(1.5); // { valid: true } * v.validate("x"); // { valid: false, errors: [{ code: "type", ... }], truncated: false } * * // Opt into the nested error tree: * const t = compileSchema({ type: "number" }, { dialect: jsonSchemaDialect, output: "tree" }); * t.validate("x"); // { valid: false, error: { code: "type", ... }, truncated: false } * ``` * * @public */ declare function compileSchema(schema: SchemaOrBoolean, options: CompileOptions & ({ output: "predicate"; } | { predicate: true; })): CompiledPredicate; declare function compileSchema(schema: SchemaOrBoolean, options: CompileOptions & { output: "tree"; }): CompiledTreeSchema; declare function compileSchema(schema: SchemaOrBoolean, options: CompileOptions & { output?: "flat" | undefined; predicate?: false | undefined; }): CompiledSchema; declare function compileSchema(schema: SchemaOrBoolean, options: CompileOptions): CompiledSchema | CompiledTreeSchema | CompiledPredicate; export { type CompileOptions as C, type FlatValidationResult as F, type StrictIssue as S, type TreeValidationResult as T, type ValidationResult as V, type CompileStats as a, type CompiledFlatSchema as b, type CompiledPredicate as c, type CompiledSchema as d, type CompiledTreeSchema as e, compileSchema as f, schemaUsesUnevaluated as s };