import { BlockNodeAddress, BlockNodeType, NodeAddress } from './base.js'; import { SelectionTarget } from './address.js'; import { TextSelector, NodeSelector } from './query.js'; import { DiscoveryItem, DiscoveryResult } from './discovery.js'; import { InlineToggleDirective } from './style-policy.types.js'; import { StoryLocator } from './story.types.js'; export type CardinalityRequirement = 'any' | 'first' | 'exactlyOne' | 'all'; /** Maximum total length for a match snippet (D11). */ export declare const SNIPPET_MAX_LENGTH = 500; /** Maximum characters of surrounding context on each side of the match (D11). */ export declare const SNIPPET_CONTEXT_CHARS = 100; /** * Character offsets within a snippet identifying the matched text. * * Invariants (D17): * - `start >= 0 && end <= snippet.length` * - `start < end` (zero-width matches are dropped before snippet assembly per D20) */ export interface HighlightRange { start: number; end: number; } /** Direct toggle states: what the run explicitly declares at run level. */ export interface MatchDirectStyles { bold: InlineToggleDirective; italic: InlineToggleDirective; underline: InlineToggleDirective; strike: InlineToggleDirective; } /** Effective visual states: what the user sees after style cascade resolution. */ export interface MatchEffectiveStyles { bold: boolean; italic: boolean; underline: boolean; strike: boolean; } /** * Two-layer inline style state for a single run. * * - `direct`: tri-state directives reflecting the run's explicit formatting. * - `effective`: boolean visual state after style cascade resolution. * - Non-toggle properties remain at top level. */ export interface MatchStyle { direct: MatchDirectStyles; effective: MatchEffectiveStyles; /** 6-digit lowercase hex with `#` prefix (e.g., `#ff0000`). */ color?: string; /** 6-digit lowercase hex with `#` prefix. */ highlight?: string; /** Raw font family string from the document (e.g., `"Calibri"`). */ fontFamily?: string; /** Font size in points, rounded to 1 decimal place. */ fontSizePt?: number; } /** * A contiguous span of text within a block sharing identical mark-signature. * * Invariant (D4: run-tiling): within a block, runs exactly tile the block's * matched range with no gaps and no overlaps. */ export interface MatchRun { /** Block-relative character offsets. */ range: { start: number; end: number; }; /** The text content of this run. */ text: string; /** * OOXML character style definition ID (`w:rStyle` `w:val`): the key into * `styles.xml`. Omitted when no character style is applied (D10a). */ styleId?: string; /** Resolved inline style state for this run. */ styles: MatchStyle; /** Run-scoped ephemeral ref (V3, scope: 'run'). */ ref: string; } /** * A single block's participation in a logical match. * Contains the block-scoped text and its decomposition into style runs. */ export interface MatchBlock { /** The PM node's stable block ID. */ blockId: string; /** The PM node type name (e.g., 'paragraph', 'heading', 'listItem'). */ nodeType: BlockNodeType | string; /** Block-relative character offsets of the match within this block. */ range: { start: number; end: number; }; /** The matched text within this block. */ text: string; /** * Paragraph-level style metadata (D10). * `styleId` is the OOXML paragraph style definition ID (`w:pStyle` `w:val`). * Omitted when no paragraph style metadata is available. */ paragraphStyle?: { styleId?: string; isListItem?: boolean; listLevel?: number; }; /** Block-scoped ephemeral ref (V3, scope: 'block'). */ ref: string; /** * Style runs within the matched range, in offset order (D16). * Runs exactly tile `range` (D4 invariant). */ runs: MatchRun[]; } /** * Domain fields for a text-selector match. * * Always has blocks, snippet, highlightRange (D18). * `blocks` is a non-empty tuple: a text match always covers at least one block. */ export interface TextMatchDomain { /** Discriminator: always `'text'` for text-selector matches. */ matchKind: 'text'; /** Address of the containing block in document order (D14). Text matches always yield the block. */ address: BlockNodeAddress; /** * Canonical mutation-ready selection target for this text match. * * Can be passed directly to `doc.delete({ target })`, `doc.replace({ target, text })`, * or `doc.format.apply({ target, inline })` for cross-block mutations. */ target: SelectionTarget; /** Matched text plus surrounding context (D11). */ snippet: string; /** Character offsets within `snippet` identifying the matched text (D17). */ highlightRange: HighlightRange; /** Block decomposition of the match, in document order (D16). */ blocks: [MatchBlock, ...MatchBlock[]]; } /** * Domain fields for a node-selector match. * * No blocks, no snippet (D13, D18). * Block-level nodes use a stable nodeId ref. Inline nodes use an ephemeral * V3 ref (anchor offsets are position-dependent). */ export interface NodeMatchDomain { /** Discriminator: always `'node'` for node-selector matches. */ matchKind: 'node'; /** Address of the first matched block in document order (D14). */ address: NodeAddress; /** Always empty for node matches. Discriminator: `blocks.length === 0`. */ blocks: []; } /** Discriminated union of match domain types. Use `matchKind` as the canonical discriminator (`'text'` or `'node'`). */ export type QueryMatchDomain = TextMatchDomain | NodeMatchDomain; /** A single match item in the discovery envelope. */ export type QueryMatchItem = DiscoveryItem; /** Text match item (blocks.length > 0). */ export type TextMatchItem = DiscoveryItem; /** Node match item (blocks.length === 0). */ export type NodeMatchItem = DiscoveryItem; /** * Metadata for `query.match`: always present on the output envelope. * * - `effectiveResolved: true`: converter context was available; `styles.effective` * on every run reflects full cascade resolution. * - `effectiveResolved: false`: converter context was unavailable (headless/non-DOCX); * `styles.effective` is derived from `direct` only. */ export interface QueryMatchMeta { effectiveResolved: boolean; } export interface QueryMatchInput { select: TextSelector | NodeSelector; within?: BlockNodeAddress; /** Restrict matching to a specific story. Omit for body (backward compatible). */ in?: StoryLocator; require?: CardinalityRequirement; /** Match evaluation mode. `'candidates'` (default) returns best-effort matches; `'strict'` enforces exact semantics (future). */ mode?: 'strict' | 'candidates'; includeNodes?: boolean; limit?: number; offset?: number; } /** * Standardized discovery output for `query.match`. * * Narrows the shared `DiscoveryResult` envelope so that `meta: QueryMatchMeta` * is **required** (not optional). SDK/client code consuming `query.match` gets * `output.meta.effectiveResolved` as a non-optional boolean. * * Items are `DiscoveryItem`: * - `id`: deterministic identity, revision-scoped (format: `m:`, D7) * - `handle`: mutation-ready `ResolvedHandle` with `ref`, `refStability`, `targetKind` * - Plus domain fields (`address`, `blocks`, `snippet`, `highlightRange`) */ export type QueryMatchOutput = Omit, QueryMatchMeta>, 'meta'> & { meta: QueryMatchMeta; }; //# sourceMappingURL=query-match.types.d.ts.map