import type { NormalizeMode } from "./normalize.js"; /** Output format the dirty text claims to be. Corpus schema.json uses "JSON"/"XML". */ export declare const Format: { readonly JSON: "JSON"; readonly XML: "XML"; }; export type Format = (typeof Format)[keyof typeof Format]; /** The coercion target kinds the engine understands. OBJECT = nested ExtractSchema. */ export declare const FieldKind: { readonly STRING: "STRING"; readonly INT: "INT"; readonly LONG: "LONG"; readonly DOUBLE: "DOUBLE"; readonly BOOLEAN: "BOOLEAN"; readonly ENUM: "ENUM"; readonly OBJECT: "OBJECT"; }; export type FieldKind = (typeof FieldKind)[keyof typeof FieldKind]; /** * FROZEN cross-port per-field extraction classification. Do not reorder or add * without an ADR. These string values are SERIALIZED in the conformance corpus. */ export declare const FieldExtraction: { readonly EXTRACTED: "EXTRACTED"; readonly DEFAULTED: "DEFAULTED"; readonly LOST_OPTIONAL: "LOST_OPTIONAL"; readonly LOST_REQUIRED: "LOST_REQUIRED"; readonly MALFORMED: "MALFORMED"; }; export type FieldExtraction = (typeof FieldExtraction)[keyof typeof FieldExtraction]; /** * STRICT: case-sensitive, minimal repair. NORMAL: case-insensitive keys/tags * (default). LOOSE: maximal repair (currently identical to NORMAL — reserved). */ export declare const Tolerance: { readonly STRICT: "STRICT"; readonly NORMAL: "NORMAL"; readonly LOOSE: "LOOSE"; }; export type Tolerance = (typeof Tolerance)[keyof typeof Tolerance]; /** A recorded normalization/coercion. kind e.g. "normalize", "alias", "runtime-alias-override", "clamp", "coerceDefault", "default". */ export interface Coercion { readonly fieldPath: string; readonly from: string; readonly to: string; readonly kind: string; } /** * One field's extract descriptor. enumValues/enumAlias non-null only for ENUM; * min/max non-null only for numeric range constraints; nested non-null only for OBJECT. */ export interface FieldSpec { readonly name: string; readonly kind: FieldKind; readonly required: boolean; readonly array: boolean; readonly enumValues: readonly string[] | null; readonly enumAlias: Readonly> | null; readonly min: number | null; readonly max: number | null; readonly nested: ExtractSchema | null; /** FR-011: present-but-uncoercible fallback member (from `@coerceDefault`). ENUM-only; null = none. */ readonly coerceDefault: string | null; /** * Absent-fill default (from `@default`). When the field is ABSENT, extract fills this value * → DEFAULTED (which satisfies `@required`). Generalized to ALL field kinds (Phase B): for an * enum it is the member string verbatim; for a non-enum it is coerced to `kind` via the pure * scalar coerce (so `@default "0"` on `field.int` yields integer 0). null = no default. */ readonly defaultValue: string | null; /** FR-011: resolved enum normalization mode (from `@normalize`; default `"strip"`). */ readonly normalize: NormalizeMode; /** * `@xmlText`: this field receives its element's TEXT CONTENT (analogous to JAXB `@XmlValue` / * Jackson `@JacksonXmlText` / .NET `[XmlText]`). The extract engine reads it from the * `#text` sentinel the lenient XML reader carries when an element has both attributes and a * text body, instead of a same-named child. Absent/false for normal fields and for JSON. */ readonly textContent?: boolean; } /** * A scalar field, optionally carrying an absent-fill `@default` (Phase B — generalized * `@default`). When ABSENT from the model response, extract coerces `defaultValue` to `kind` * and classifies the field DEFAULTED (which satisfies `@required`). `defaultValue == null` is * the no-default case (back-compat with the original two-arg call). */ export declare function scalar(name: string, kind: FieldKind, required: boolean, defaultValue?: string | null): FieldSpec; /** * A field that receives its element's TEXT CONTENT — the `@xmlText` marker (see * {@link FieldSpec.textContent}). A scalar with the `textContent` flag set; coerced to `kind`. */ export declare function textContentField(name: string, kind: FieldKind, required: boolean): FieldSpec; export declare function enumField(name: string, required: boolean, values: readonly string[] | null, aliases: Readonly> | null, coerceDefault?: string | null, normalize?: NormalizeMode, defaultValue?: string | null): FieldSpec; /** * Phase B (array-of-enum): an enum field that is a list (`array === true`). Each element flows * through the SAME enum coercion pipeline a scalar enum uses (exact → normalize → `@enumAlias` * → `@coerceDefault` → MALFORMED) and is classified independently by indexed path (`tags[0]`, * `tags[1]`, …). Mirrors {@link enumField} but with `array = true`. */ export declare function enumArray(name: string, required: boolean, values: readonly string[] | null, aliases: Readonly> | null, coerceDefault?: string | null, normalize?: NormalizeMode, defaultValue?: string | null): FieldSpec; export declare function range(name: string, kind: FieldKind, required: boolean, min: number | null, max: number | null): FieldSpec; export declare function object(name: string, required: boolean, array: boolean, nested: ExtractSchema | null): FieldSpec; /** Top-level extract descriptor. rootName = the XML root tag / logical JSON root name. */ export interface ExtractSchema { readonly format: Format; readonly rootName: string; readonly fields: readonly FieldSpec[]; } export declare function extractSchema(format: Format, rootName: string, fields: readonly FieldSpec[] | null): ExtractSchema; /** * ctx carries the field path and the FieldSpec; return null to fall through to * default coercion. The single bespoke-coercion hook (the bounded "20%"). */ export type OnField = (fieldPath: string, rawValue: string, spec: FieldSpec) => unknown | null; /** * Bounded runtime override surface. aliases/normalizers are MERGED with the * schema's, runtime winning on key conflict. onField is the single hook. * * `rootless` (XML only): when `true`, the input has NO enclosing root element — the payload's * fields ARE the top-level elements (a flat sequence like `....`). The engine * parses those top-level elements directly instead of locating a `` span, so the caller * need not synthesize a wrapper. No effect for JSON. Default `false` (a single root element is * expected, as before). Mirrors Java ExtractOptions.rootless. */ export interface ExtractOptions { readonly tolerance: Tolerance; readonly aliases: Readonly>; readonly normalizers: Readonly unknown | null>>; readonly onField: OnField | null; readonly rootless: boolean; } export declare function defaults(): ExtractOptions; /** Normalize a partial / undefined options bag into a complete ExtractOptions. */ export declare function normalizeOptions(opts?: Partial | null): ExtractOptions; /** Engine return. data is a forgiving record; Phase-2 codegen wraps it into a typed ExtractionResult. */ export interface ExtractionOutcome { readonly data: Record; readonly report: ExtractionReport; } /** Typed result of a generated extract(...): best-effort value (null where lost/malformed) + report. */ export interface ExtractionResult { readonly data: T | null; readonly report: ExtractionReport; } /** * Thrown by {@link orThrow} when a {@link ExtractionResult} lost a `@required` field. Mirrors * Java's `ExtractException`. Carries the list of lost-required field paths. */ export declare class ExtractError extends Error { readonly lostRequired: readonly string[]; constructor(lostRequired: readonly string[]); } /** * Opt-in strictness over a never-throwing {@link ExtractionResult}. Mirrors Java * `ExtractionResult.orThrow()`. Throws a {@link ExtractError} iff the report has a lost * `@required` field; otherwise returns `result.data`. * *

TS divergence from Java (documented): `ExtractionResult` is a plain interface (the generated * output-parsers build it as an object literal), so `orThrow` is a free function rather than a * method on the result. Semantics are identical.

*/ export declare function orThrow(result: ExtractionResult): T | null; /** Mutable accumulator of per-field extraction classification, the degenerate-response flag, and coercion notes. */ export declare class ExtractionReport { private readonly _states; private readonly _coercions; private readonly _defaultedRequired; private _empty; set(fieldPath: string, state: FieldExtraction): void; addCoercion(c: Coercion): void; markEmpty(): void; isEmpty(): boolean; states(): ReadonlyMap; coercions(): readonly Coercion[]; lostRequired(): string[]; malformed(): string[]; hasLostRequired(): boolean; /** Every field the document did not answer, whose value came from its `@default`. */ defaulted(): string[]; /** * The dangerous subset: **`@required` fields the document did NOT answer**, whose value * was silently supplied by their `@default`. * * These do NOT appear in `lostRequired()`, and that is deliberate — a default IS an * answer, so the field is not "lost". But it means a `@default` **switches off loss * detection for that field**, including in generated code: the generated extractor and * `dataOrThrow()` both key their failure signal on `hasLostRequired()`, so a required * field with a default can never make them fire. * * That is a sharp edge worth being able to SEE. It propagates through `extends` — adding * an innocuous `@default` to a shared abstract field silently disables loss detection for * every field inheriting it — and a missing value then becomes indistinguishable from a * real one. Check this alongside `hasLostRequired()` when an absent answer must not be * mistaken for a given one. */ defaultedRequired(): string[]; hasDefaultedRequired(): boolean; /** Called by extract when an absent **required** field is filled from its `@default`. */ markDefaultedRequired(fieldPath: string): void; private byState; } //# sourceMappingURL=types.d.ts.map