/** * DfaEngine — Deterministic Finite Automaton for content-model validation * ========================================================================= * v1.7-foundation (G28 / G27) * * Converts a compositor (xs:sequence / xs:choice / xs:all) into a compiled * DFA whose states encode which particles are currently expected and how many * times each has been seen. The DFA enables: * * • O(1) per-element validation (no linear scan of schema particles) * • Deterministic error messages ("expected but found ") * • Streaming-mode validation (no DOM required) * • Reusable per complex-type (compiled once, stored on CompiledSchema) * * Implementation notes * ──────────────────── * For v1.7-foundation we build a "NFA-lite" that is deterministic for the * common cases (sequence, fixed occurrences, choice). Full subset construction * and minimisation is deferred to v2.0. * * Public API (stable): * buildDfa(particles) → DfaModel * runDfa(dfa, children) → DfaRunResult */ import { ParticleDefinition } from '../schema/SchemaModel'; export type CompositorKind = 'sequence' | 'choice' | 'all'; export interface DfaState { /** 0-based index of the next expected particle in the content model */ particleIndex: number; /** How many times the particle at particleIndex has been seen */ seen: number; /** Whether we are in an accepted (terminal) state */ accepting: boolean; } export interface DfaTransition { /** Name of the element that triggers this transition (or '*' for wildcard) */ elementName: string; /** Source state index */ from: number; /** Target state index */ to: number; /** Particle index consumed by this transition */ particleIndex: number; } export interface DfaModel { kind: CompositorKind; particles: NormalisedParticle[]; states: DfaState[]; transitions: DfaTransition[]; /** Index of the unique initial state */ initial: number; /** Set of accepting state indices */ accepting: Set; /** * O(1) lookup index: element name → particle. * The '*' wildcard particle (if any) is stored under the key '*'. * Built once in buildDfa; used by _runAll and _runChoice to avoid O(n) scans. */ particleIndex: Map; } export interface NormalisedParticle { name: string; minOccurs: number; maxOccurs: number; isGroup: boolean; nested?: DfaModel; } export interface DfaRunResult { valid: boolean; /** Elements that were found but not expected at that position */ unexpected: string[]; /** Particle names that were required but absent */ missing: string[]; /** Element names that exceeded maxOccurs */ tooMany: string[]; } /** * Build a DFA model from a flat particle list and compositor kind. * For v1.7-foundation we build a lightweight NFA-lite: * • sequence → linear state chain with occurrence guards * • choice → fan-out from state 0 to each particle's accepting state * • all → bitmask-based acceptance (order-independent) * * NP2-16 fix: cycle detection guard added via `_buildDepth` parameter to * prevent infinite recursion on mutually-recursive group references. */ export declare function buildDfa(particles: ParticleDefinition[], kind?: CompositorKind, _buildDepth?: number): DfaModel; /** * Evaluate a DFA against a list of element names. * Returns a DfaRunResult describing any structural violations. */ export declare function runDfa(dfa: DfaModel, elementNames: string[]): DfaRunResult; //# sourceMappingURL=DfaEngine.d.ts.map