@reticular/speakable 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -2
- package/dist/browser/index.d.ts +58 -0
- package/dist/browser/index.js +3978 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/chunk-WYFXGXYU.js +87 -0
- package/dist/chunk-WYFXGXYU.js.map +1 -0
- package/dist/cli.js +40 -19
- package/dist/cli.js.map +1 -1
- package/dist/harness/index.d.ts +57 -0
- package/dist/harness/index.js +176 -0
- package/dist/harness/index.js.map +1 -0
- package/dist/index.js +44 -22
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +40 -19
- package/dist/mcp.js.map +1 -1
- package/dist/speakable-browser.global.js +10 -0
- package/dist/speakable-browser.global.js.map +1 -0
- package/dist/storybook/dist/chunk-3SVI6IQE.js +86 -0
- package/dist/storybook/dist/chunk-JSBRDJBE.js +30 -0
- package/dist/storybook/dist/chunk-QVJRQZT5.js +16 -0
- package/dist/storybook/dist/index.js +17 -0
- package/dist/storybook/dist/manager.js +701 -0
- package/dist/storybook/dist/preset.js +38 -0
- package/dist/storybook/dist/preview.js +4199 -0
- package/dist/storybook/dist/upgrade-5GL42JH4.js +7 -0
- package/dist/types-Blh0EnZF.d.ts +213 -0
- package/dist/upgrade-53M5VYGH.js +7 -0
- package/dist/upgrade-53M5VYGH.js.map +1 -0
- package/package.json +28 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/model/types.ts","../src/model/validation.ts","../src/model/serialization.ts","../src/diff/diff-algorithm.ts","../src/diff/formatter.ts","../src/cli/colors.ts","../src/renderer/nvda-renderer.ts","../src/renderer/jaws-renderer.ts","../src/renderer/voiceover-renderer.ts","../src/renderer/narrator-renderer.ts","../src/renderer/audit-renderer.ts","../src/parser/html-parser.ts","../src/extractor/aria-name.ts","../src/extractor/role-mapper.ts","../src/extractor/state-extractor.ts","../src/extractor/focus-extractor.ts","../src/extractor/tree-builder.ts","../src/runtime/index.ts","../src/runtime/selector.ts","../src/runtime/observers/focus-observer.ts","../src/runtime/observers/mutation-observer.ts","../src/runtime/observers/live-region-observer.ts","../src/runtime/observers/dialog-observer.ts","../src/runtime/engine.ts","../src/runtime/interactions.ts","../src/runtime/heuristics.ts","../src/runtime/timeline-generator.ts","../src/runtime/patterns.ts","../src/runtime/serialization.ts","../src/runtime/diff-engine.ts","../src/runtime/severity.ts","../src/runtime/baseline-storage.ts","../src/runtime/verbosity-analyzer.ts"],"sourcesContent":["/**\n * Canonical Announcement Model - Version 1\n * \n * Platform-agnostic representation of accessibility semantics.\n * Deterministic, serializable, suitable for snapshot testing.\n */\n\n/**\n * Model version for forward compatibility.\n * Breaking changes increment major version.\n */\nexport interface ModelVersion {\n major: number;\n minor: number;\n}\n\n/**\n * Accessible role following ARIA specification.\n * V1 supports common interactive and structural roles.\n */\nexport type AccessibleRole =\n // Interactive elements\n | 'button'\n | 'link'\n | 'heading'\n | 'textbox'\n | 'checkbox'\n | 'radio'\n | 'combobox'\n | 'listbox'\n | 'option'\n // Structural\n | 'list'\n | 'listitem'\n | 'article'\n | 'generic'\n // Landmarks\n | 'navigation'\n | 'main'\n | 'banner'\n | 'contentinfo'\n | 'region'\n | 'img'\n | 'complementary'\n | 'form'\n | 'search'\n // Static content (new)\n | 'paragraph'\n | 'blockquote'\n | 'code'\n | 'staticText'\n // Tables (new)\n | 'table'\n | 'row'\n | 'cell'\n | 'columnheader'\n | 'rowheader'\n // Definition lists (new)\n | 'term'\n | 'definition'\n // Figures (new)\n | 'figure'\n | 'caption'\n // Grouping & disclosure (new)\n | 'group'\n | 'dialog'\n // Widgets (new)\n | 'meter'\n | 'progressbar'\n | 'status'\n // Embedded content (new)\n | 'document'\n | 'application'\n | 'separator';\n\n/**\n * Accessible states and properties.\n * Only includes properties relevant to the element's role.\n */\nexport interface AccessibleState {\n /** Whether the element is expanded (e.g., accordion, dropdown) */\n expanded?: boolean;\n \n /** Whether the element is checked (checkbox, radio, or mixed state) */\n checked?: boolean | 'mixed';\n \n /** Whether the element is pressed (toggle button) */\n pressed?: boolean | 'mixed';\n \n /** Whether the element is selected (option, tab, etc.) */\n selected?: boolean;\n \n /** Whether the element is disabled */\n disabled?: boolean;\n \n /** Whether the element has invalid input */\n invalid?: boolean;\n \n /** Whether the element is required */\n required?: boolean;\n \n /** Whether the element is read-only */\n readonly?: boolean;\n \n /** Whether the element is busy loading */\n busy?: boolean;\n \n /** Current page/step/location indicator */\n current?: 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | false;\n \n /** Whether the element is grabbed for drag-and-drop */\n grabbed?: boolean;\n \n /** Whether the element is hidden from accessibility tree */\n hidden?: boolean;\n \n /** Heading level (1-6) */\n level?: number;\n \n /** Position in set (1-indexed) for lists, tabs, etc. */\n posinset?: number;\n \n /** Total size of set */\n setsize?: number;\n}\n\n/**\n * Value for form controls and range widgets.\n */\nexport interface AccessibleValue {\n /** Current value */\n current: string | number;\n \n /** Minimum value (for range widgets) */\n min?: number;\n \n /** Maximum value (for range widgets) */\n max?: number;\n \n /** Textual representation (e.g., \"50%\") */\n text?: string;\n}\n\n/**\n * Focusability information.\n */\nexport interface FocusInfo {\n /** Whether the element can receive focus */\n focusable: boolean;\n \n /** Explicit tabindex value (only present if explicitly set) */\n tabindex?: number;\n}\n\n/**\n * Single node in the accessibility tree.\n */\nexport interface AccessibleNode {\n /** ARIA role of the element */\n role: AccessibleRole;\n \n /** Accessible name (computed via ARIA name algorithm) */\n name: string;\n \n /** Accessible description (aria-describedby, title, etc.) */\n description?: string;\n \n /** Value for form controls */\n value?: AccessibleValue;\n \n /** State properties */\n state: AccessibleState;\n \n /** Focus information */\n focus: FocusInfo;\n \n /** Child nodes in the accessibility tree */\n children: AccessibleNode[];\n}\n\n/**\n * Root of the Canonical Announcement Model.\n */\nexport interface AnnouncementModel {\n /** Model version for forward compatibility */\n version: ModelVersion;\n \n /** Root node of the accessibility tree */\n root: AccessibleNode;\n \n /** Metadata about the extraction */\n metadata: {\n /** ISO 8601 timestamp of extraction */\n extractedAt: string;\n \n /** Optional hash of source HTML for change detection */\n sourceHash?: string;\n };\n}\n\n/**\n * Supported roles as a constant array for validation.\n */\nexport const SUPPORTED_ROLES: readonly AccessibleRole[] = [\n // Original roles (22)\n 'button',\n 'link',\n 'heading',\n 'textbox',\n 'checkbox',\n 'radio',\n 'combobox',\n 'listbox',\n 'option',\n 'list',\n 'listitem',\n 'navigation',\n 'main',\n 'banner',\n 'contentinfo',\n 'region',\n 'img',\n 'article',\n 'complementary',\n 'form',\n 'search',\n 'generic',\n // New roles (21)\n 'paragraph',\n 'blockquote',\n 'code',\n 'staticText',\n 'table',\n 'row',\n 'cell',\n 'columnheader',\n 'rowheader',\n 'term',\n 'definition',\n 'figure',\n 'caption',\n 'group',\n 'dialog',\n 'meter',\n 'progressbar',\n 'status',\n 'document',\n 'application',\n 'separator',\n] as const;\n\n/**\n * Current model version constant.\n */\nexport const CURRENT_MODEL_VERSION: ModelVersion = {\n major: 1,\n minor: 0,\n};\n","/**\n * Validation functions for the Canonical Announcement Model.\n */\n\nimport type {\n AccessibleNode,\n AccessibleRole,\n AccessibleState,\n AnnouncementModel,\n} from './types.js';\nimport { SUPPORTED_ROLES } from './types.js';\n\n/**\n * Validation error class.\n */\nexport class ValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Validates that a role is supported in V1.\n * \n * @param role - The role to validate\n * @returns true if valid\n * @throws ValidationError if invalid\n */\nexport function validateRole(role: string): role is AccessibleRole {\n if (!SUPPORTED_ROLES.includes(role as AccessibleRole)) {\n throw new ValidationError(\n `Invalid role: \"${role}\". Supported roles: ${SUPPORTED_ROLES.join(', ')}`\n );\n }\n return true;\n}\n\n/**\n * Validates accessible state constraints.\n * \n * @param state - The state object to validate\n * @throws ValidationError if invalid\n */\nexport function validateState(state: AccessibleState): void {\n // Validate level is in range 1-6 for headings\n if (state.level !== undefined) {\n if (!Number.isInteger(state.level) || state.level < 1 || state.level > 6) {\n throw new ValidationError(\n `Invalid heading level: ${state.level}. Must be an integer between 1 and 6.`\n );\n }\n }\n\n // Validate posinset is positive\n if (state.posinset !== undefined) {\n if (!Number.isInteger(state.posinset) || state.posinset < 1) {\n throw new ValidationError(\n `Invalid posinset: ${state.posinset}. Must be a positive integer.`\n );\n }\n }\n\n // Validate setsize is positive\n if (state.setsize !== undefined) {\n if (!Number.isInteger(state.setsize) || state.setsize < 1) {\n throw new ValidationError(\n `Invalid setsize: ${state.setsize}. Must be a positive integer.`\n );\n }\n }\n\n // Validate posinset <= setsize if both present\n if (\n state.posinset !== undefined &&\n state.setsize !== undefined &&\n state.posinset > state.setsize\n ) {\n throw new ValidationError(\n `Invalid set position: posinset (${state.posinset}) cannot exceed setsize (${state.setsize}).`\n );\n }\n\n // Validate checked is boolean or 'mixed'\n if (state.checked !== undefined) {\n if (typeof state.checked !== 'boolean' && state.checked !== 'mixed') {\n throw new ValidationError(\n `Invalid checked value: ${state.checked}. Must be boolean or 'mixed'.`\n );\n }\n }\n\n // Validate pressed is boolean or 'mixed'\n if (state.pressed !== undefined) {\n if (typeof state.pressed !== 'boolean' && state.pressed !== 'mixed') {\n throw new ValidationError(\n `Invalid pressed value: ${state.pressed}. Must be boolean or 'mixed'.`\n );\n }\n }\n\n // Validate current is valid enum value\n if (state.current !== undefined) {\n const validCurrentValues = ['page', 'step', 'location', 'date', 'time', 'true', false];\n if (!validCurrentValues.includes(state.current as any)) {\n throw new ValidationError(\n `Invalid current value: ${state.current}. Must be one of: ${validCurrentValues.join(', ')}`\n );\n }\n }\n}\n\n/**\n * Validates tree structure integrity (no cycles).\n * \n * @param node - The root node to validate\n * @param visited - Set of visited nodes (for cycle detection)\n * @throws ValidationError if cycles detected\n */\nexport function validateTreeStructure(\n node: AccessibleNode,\n visited: Set<AccessibleNode> = new Set()\n): void {\n // Check for cycles\n if (visited.has(node)) {\n throw new ValidationError(\n 'Circular reference detected in accessibility tree. Tree must be acyclic.'\n );\n }\n\n visited.add(node);\n\n // Validate role\n validateRole(node.role);\n\n // Validate state\n validateState(node.state);\n\n // Recursively validate children\n for (const child of node.children) {\n validateTreeStructure(child, new Set(visited));\n }\n}\n\n/**\n * Validates an entire AnnouncementModel.\n * \n * @param model - The model to validate\n * @throws ValidationError if invalid\n */\nexport function validateModel(model: AnnouncementModel): void {\n // Validate version\n if (!model.version || typeof model.version.major !== 'number' || typeof model.version.minor !== 'number') {\n throw new ValidationError('Invalid model version. Must have major and minor number fields.');\n }\n\n // Validate metadata\n if (!model.metadata || !model.metadata.extractedAt) {\n throw new ValidationError('Invalid metadata. Must have extractedAt timestamp.');\n }\n\n // Validate timestamp is ISO 8601\n const timestamp = new Date(model.metadata.extractedAt);\n if (isNaN(timestamp.getTime())) {\n throw new ValidationError(\n `Invalid extractedAt timestamp: ${model.metadata.extractedAt}. Must be ISO 8601 format.`\n );\n }\n\n // Validate root node and tree structure\n if (!model.root) {\n throw new ValidationError('Model must have a root node.');\n }\n\n validateTreeStructure(model.root);\n}\n","/**\n * JSON serialization and deserialization for the Canonical Announcement Model.\n * \n * Ensures deterministic output with consistent property ordering.\n */\n\nimport type { AnnouncementModel, AccessibleNode } from './types.js';\nimport { CURRENT_MODEL_VERSION } from './types.js';\nimport { validateModel } from './validation.js';\n\n/**\n * Serialization options.\n */\nexport interface SerializationOptions {\n /** Whether to pretty-print the JSON output */\n pretty?: boolean;\n \n /** Whether to validate the model before serialization */\n validate?: boolean;\n}\n\n/**\n * Deserialization options.\n */\nexport interface DeserializationOptions {\n /** Whether to validate the model after deserialization */\n validate?: boolean;\n}\n\n/**\n * Sorts object keys to ensure deterministic JSON output.\n * \n * @param obj - Object to sort\n * @returns New object with sorted keys\n */\nfunction sortObjectKeys<T extends Record<string, any>>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys) as any as T;\n }\n\n const sorted: Record<string, any> = {};\n const keys = Object.keys(obj).sort();\n\n for (const key of keys) {\n const value = obj[key];\n sorted[key] = typeof value === 'object' && value !== null \n ? sortObjectKeys(value) \n : value;\n }\n\n return sorted as T;\n}\n\n/**\n * Serializes an AnnouncementModel to JSON string.\n * \n * Produces deterministic output with consistent property ordering.\n * \n * @param model - The model to serialize\n * @param options - Serialization options\n * @returns JSON string representation\n * @throws ValidationError if validation is enabled and model is invalid\n */\nexport function serializeModel(\n model: AnnouncementModel,\n options: SerializationOptions = {}\n): string {\n const { pretty = false, validate = true } = options;\n\n // Validate model if requested\n if (validate) {\n validateModel(model);\n }\n\n // Sort keys for deterministic output\n const sorted = sortObjectKeys(model);\n\n // Serialize with optional pretty printing\n return pretty \n ? JSON.stringify(sorted, null, 2)\n : JSON.stringify(sorted);\n}\n\n/**\n * Deserializes a JSON string to an AnnouncementModel.\n * \n * @param json - JSON string to deserialize\n * @param options - Deserialization options\n * @returns Parsed AnnouncementModel\n * @throws SyntaxError if JSON is invalid\n * @throws ValidationError if validation is enabled and model is invalid\n */\nexport function deserializeModel(\n json: string,\n options: DeserializationOptions = {}\n): AnnouncementModel {\n const { validate = true } = options;\n\n // Parse JSON\n const model = JSON.parse(json) as AnnouncementModel;\n\n // Validate model if requested\n if (validate) {\n validateModel(model);\n }\n\n return model;\n}\n\n/**\n * Creates a new AnnouncementModel with current version and timestamp.\n * \n * @param root - Root accessible node\n * @param sourceHash - Optional hash of source HTML\n * @returns New AnnouncementModel\n */\nexport function createModel(\n root: AccessibleNode,\n sourceHash?: string\n): AnnouncementModel {\n return {\n version: { ...CURRENT_MODEL_VERSION },\n root,\n metadata: {\n extractedAt: new Date().toISOString(),\n ...(sourceHash && { sourceHash }),\n },\n };\n}\n\n/**\n * Compares two models for equality (deep comparison).\n * \n * @param a - First model\n * @param b - Second model\n * @returns true if models are equivalent\n */\nexport function modelsEqual(a: AnnouncementModel, b: AnnouncementModel): boolean {\n // Simple approach: serialize both and compare strings\n // This works because serialization is deterministic\n const jsonA = serializeModel(a, { validate: false });\n const jsonB = serializeModel(b, { validate: false });\n return jsonA === jsonB;\n}\n\n/**\n * Clones a model (deep copy).\n * \n * @param model - Model to clone\n * @returns Deep copy of the model\n */\nexport function cloneModel(model: AnnouncementModel): AnnouncementModel {\n const json = serializeModel(model, { validate: false });\n return deserializeModel(json, { validate: false });\n}\n","/**\n * Semantic diff algorithm for accessibility trees.\n * \n * Compares two accessibility trees and identifies:\n * - Added nodes (present in new tree, not in old)\n * - Removed nodes (present in old tree, not in new)\n * - Changed nodes (same path, different properties)\n */\n\nimport type { AccessibleNode, AccessibleState, AccessibleValue, FocusInfo } from '../model/types.js';\nimport type { SemanticDiff, NodeChange, PropertyChange, NodePath } from './types.js';\n\n/**\n * Compare two accessibility trees and generate a semantic diff.\n * \n * @param oldTree - The original accessibility tree\n * @param newTree - The updated accessibility tree\n * @returns Semantic diff with all detected changes\n */\nexport function diffAccessibilityTrees(\n oldTree: AccessibleNode,\n newTree: AccessibleNode\n): SemanticDiff {\n const changes: NodeChange[] = [];\n \n // Build maps of path -> node for both trees\n const oldNodes = buildNodeMap(oldTree, 'root');\n const newNodes = buildNodeMap(newTree, 'root');\n \n // Find removed nodes (in old but not in new)\n for (const [path, node] of oldNodes) {\n if (!newNodes.has(path)) {\n changes.push({\n type: 'removed',\n path,\n node,\n });\n }\n }\n \n // Find added nodes (in new but not in old)\n for (const [path, node] of newNodes) {\n if (!oldNodes.has(path)) {\n changes.push({\n type: 'added',\n path,\n node,\n });\n }\n }\n \n // Find changed nodes (in both but with different properties)\n for (const [path, oldNode] of oldNodes) {\n const newNode = newNodes.get(path);\n if (newNode) {\n const propertyChanges = compareNodes(oldNode, newNode);\n if (propertyChanges.length > 0) {\n changes.push({\n type: 'changed',\n path,\n changes: propertyChanges,\n });\n }\n }\n }\n \n // Sort changes by path for deterministic output\n changes.sort((a, b) => a.path.localeCompare(b.path));\n \n // Calculate summary statistics\n const summary = {\n added: changes.filter(c => c.type === 'added').length,\n removed: changes.filter(c => c.type === 'removed').length,\n changed: changes.filter(c => c.type === 'changed').length,\n total: changes.length,\n };\n \n return { changes, summary };\n}\n\n/**\n * Build a map of path -> node for a tree.\n * \n * @param node - Root node of the tree\n * @param path - Current path (starts with 'root')\n * @returns Map of paths to nodes\n */\nfunction buildNodeMap(\n node: AccessibleNode,\n path: NodePath\n): Map<NodePath, AccessibleNode> {\n const map = new Map<NodePath, AccessibleNode>();\n \n // Add current node\n map.set(path, node);\n \n // Recursively add children\n node.children.forEach((child, index) => {\n const childPath = `${path}.children[${index}]`;\n const childMap = buildNodeMap(child, childPath);\n for (const [childPath, childNode] of childMap) {\n map.set(childPath, childNode);\n }\n });\n \n return map;\n}\n\n/**\n * Compare two nodes and identify property changes.\n * \n * @param oldNode - Original node\n * @param newNode - Updated node\n * @returns Array of property changes\n */\nfunction compareNodes(\n oldNode: AccessibleNode,\n newNode: AccessibleNode\n): PropertyChange[] {\n const changes: PropertyChange[] = [];\n \n // Compare role\n if (oldNode.role !== newNode.role) {\n changes.push({\n property: 'role',\n oldValue: oldNode.role,\n newValue: newNode.role,\n });\n }\n \n // Compare name\n if (oldNode.name !== newNode.name) {\n changes.push({\n property: 'name',\n oldValue: oldNode.name,\n newValue: newNode.name,\n });\n }\n \n // Compare description\n if (oldNode.description !== newNode.description) {\n changes.push({\n property: 'description',\n oldValue: oldNode.description,\n newValue: newNode.description,\n });\n }\n \n // Compare value\n if (!valuesEqual(oldNode.value, newNode.value)) {\n changes.push({\n property: 'value',\n oldValue: oldNode.value,\n newValue: newNode.value,\n });\n }\n \n // Compare state\n if (!statesEqual(oldNode.state, newNode.state)) {\n changes.push({\n property: 'state',\n oldValue: oldNode.state,\n newValue: newNode.state,\n });\n }\n \n // Compare focus\n if (!focusEqual(oldNode.focus, newNode.focus)) {\n changes.push({\n property: 'focus',\n oldValue: oldNode.focus,\n newValue: newNode.focus,\n });\n }\n \n return changes;\n}\n\n/**\n * Compare two AccessibleValue objects for equality.\n */\nfunction valuesEqual(\n a: AccessibleValue | undefined,\n b: AccessibleValue | undefined\n): boolean {\n if (a === undefined && b === undefined) return true;\n if (a === undefined || b === undefined) return false;\n \n return (\n a.current === b.current &&\n a.min === b.min &&\n a.max === b.max &&\n a.text === b.text\n );\n}\n\n/**\n * Compare two AccessibleState objects for equality.\n */\nfunction statesEqual(\n a: AccessibleState,\n b: AccessibleState\n): boolean {\n // Get all unique keys from both states\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n \n for (const key of keys) {\n const aValue = a[key as keyof AccessibleState];\n const bValue = b[key as keyof AccessibleState];\n \n if (aValue !== bValue) {\n return false;\n }\n }\n \n return true;\n}\n\n/**\n * Compare two FocusInfo objects for equality.\n */\nfunction focusEqual(\n a: FocusInfo,\n b: FocusInfo\n): boolean {\n return (\n a.focusable === b.focusable &&\n a.tabindex === b.tabindex\n );\n}\n\n/**\n * Generate a human-readable description of a change.\n * \n * @param change - The change to describe\n * @returns Human-readable description\n */\nexport function describeChange(change: NodeChange): string {\n switch (change.type) {\n case 'added':\n return `Added ${change.node?.role} \"${change.node?.name}\" at ${change.path}`;\n \n case 'removed':\n return `Removed ${change.node?.role} \"${change.node?.name}\" from ${change.path}`;\n \n case 'changed': {\n const descriptions = change.changes?.map(pc => {\n const oldVal = formatValue(pc.oldValue);\n const newVal = formatValue(pc.newValue);\n return `${pc.property}: ${oldVal} → ${newVal}`;\n }) || [];\n return `Changed at ${change.path}: ${descriptions.join(', ')}`;\n }\n \n default:\n return `Unknown change at ${change.path}`;\n }\n}\n\n/**\n * Format a value for display in change descriptions.\n */\nfunction formatValue(value: unknown): string {\n if (value === undefined) return 'undefined';\n if (value === null) return 'null';\n if (typeof value === 'string') return `\"${value}\"`;\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n}\n","/**\n * Formatting utilities for semantic diff output.\n * \n * Provides JSON and human-readable text formatting for diffs.\n */\n\nimport type { SemanticDiff, PropertyChange } from './types.js';\n\n/**\n * Format a semantic diff as pretty-printed JSON.\n * \n * @param diff - The semantic diff to format\n * @returns JSON string with 2-space indentation\n */\nexport function formatDiffAsJSON(diff: SemanticDiff): string {\n return JSON.stringify(diff, null, 2);\n}\n\n/**\n * Format a semantic diff as human-readable text.\n * \n * @param diff - The semantic diff to format\n * @returns Multi-line text description of changes\n */\nexport function formatDiffAsText(diff: SemanticDiff): string {\n const lines: string[] = [];\n \n // Summary header\n lines.push('=== Accessibility Tree Diff ===');\n lines.push('');\n lines.push(`Total changes: ${diff.summary.total}`);\n lines.push(` Added: ${diff.summary.added}`);\n lines.push(` Removed: ${diff.summary.removed}`);\n lines.push(` Changed: ${diff.summary.changed}`);\n lines.push('');\n \n if (diff.changes.length === 0) {\n lines.push('No changes detected.');\n return lines.join('\\n');\n }\n \n // Group changes by type\n const added = diff.changes.filter(c => c.type === 'added');\n const removed = diff.changes.filter(c => c.type === 'removed');\n const changed = diff.changes.filter(c => c.type === 'changed');\n \n // Added nodes\n if (added.length > 0) {\n lines.push('--- Added Nodes ---');\n for (const change of added) {\n lines.push(`+ ${change.path}`);\n lines.push(` Role: ${change.node?.role}`);\n lines.push(` Name: \"${change.node?.name}\"`);\n if (change.node?.description) {\n lines.push(` Description: \"${change.node.description}\"`);\n }\n lines.push('');\n }\n }\n \n // Removed nodes\n if (removed.length > 0) {\n lines.push('--- Removed Nodes ---');\n for (const change of removed) {\n lines.push(`- ${change.path}`);\n lines.push(` Role: ${change.node?.role}`);\n lines.push(` Name: \"${change.node?.name}\"`);\n if (change.node?.description) {\n lines.push(` Description: \"${change.node.description}\"`);\n }\n lines.push('');\n }\n }\n \n // Changed nodes\n if (changed.length > 0) {\n lines.push('--- Changed Nodes ---');\n for (const change of changed) {\n lines.push(`~ ${change.path}`);\n if (change.changes) {\n for (const propChange of change.changes) {\n lines.push(` ${formatPropertyChange(propChange)}`);\n }\n }\n lines.push('');\n }\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Format a single property change as text.\n */\nfunction formatPropertyChange(change: PropertyChange): string {\n const oldVal = formatValue(change.oldValue);\n const newVal = formatValue(change.newValue);\n return `${change.property}: ${oldVal} → ${newVal}`;\n}\n\n/**\n * Format a value for display.\n */\nfunction formatValue(value: unknown): string {\n if (value === undefined) return 'undefined';\n if (value === null) return 'null';\n if (typeof value === 'string') return `\"${value}\"`;\n if (typeof value === 'object') {\n // For objects, show a compact representation\n const json = JSON.stringify(value);\n if (json.length > 50) {\n return json.substring(0, 47) + '...';\n }\n return json;\n }\n return String(value);\n}\n\n/**\n * Format a semantic diff for CI/CD tools (GitHub Actions, GitLab CI, etc.).\n * \n * Uses a format that's easy to parse and diff-friendly.\n * \n * @param diff - The semantic diff to format\n * @returns CI-friendly text output\n */\nexport function formatDiffForCI(diff: SemanticDiff): string {\n const lines: string[] = [];\n \n // Machine-readable summary line\n lines.push(`DIFF_SUMMARY: added=${diff.summary.added} removed=${diff.summary.removed} changed=${diff.summary.changed} total=${diff.summary.total}`);\n lines.push('');\n \n // One line per change for easy parsing\n for (const change of diff.changes) {\n switch (change.type) {\n case 'added':\n lines.push(`ADDED: ${change.path} | role=${change.node?.role} | name=\"${change.node?.name}\"`);\n break;\n \n case 'removed':\n lines.push(`REMOVED: ${change.path} | role=${change.node?.role} | name=\"${change.node?.name}\"`);\n break;\n \n case 'changed':\n const props = change.changes?.map(pc => \n `${pc.property}:${formatValue(pc.oldValue)}->${formatValue(pc.newValue)}`\n ).join(' | ') || '';\n lines.push(`CHANGED: ${change.path} | ${props}`);\n break;\n }\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Check if a diff represents a regression (accessibility got worse).\n * \n * Heuristics:\n * - Removed nodes with important roles (button, link, heading, etc.)\n * - Changed nodes that lost accessible names\n * - Changed nodes that became disabled or hidden\n * \n * @param diff - The semantic diff to analyze\n * @returns True if potential regression detected\n */\nexport function hasAccessibilityRegression(diff: SemanticDiff): boolean {\n const importantRoles = new Set([\n 'button', 'link', 'heading', 'textbox', 'checkbox', 'radio',\n 'navigation', 'main', 'banner', 'contentinfo', 'form', 'search'\n ]);\n \n // Check for removed important nodes\n for (const change of diff.changes) {\n if (change.type === 'removed' && change.node?.role && importantRoles.has(change.node.role)) {\n return true;\n }\n \n // Check for nodes that lost their accessible name\n if (change.type === 'changed' && change.changes) {\n for (const propChange of change.changes) {\n if (propChange.property === 'name') {\n const oldName = propChange.oldValue as string;\n const newName = propChange.newValue as string;\n if (oldName && !newName) {\n return true;\n }\n }\n \n // Check for nodes that became hidden or disabled\n if (propChange.property === 'state') {\n const oldState = propChange.oldValue as any;\n const newState = propChange.newValue as any;\n if (!oldState?.hidden && newState?.hidden) {\n return true;\n }\n if (!oldState?.disabled && newState?.disabled) {\n return true;\n }\n }\n }\n }\n }\n \n return false;\n}\n","import pc from 'picocolors';\n\nexport interface ColorFunctions {\n // Semantic colors for audit report\n error: (s: string) => string;\n warning: (s: string) => string;\n info: (s: string) => string;\n success: (s: string) => string;\n heading: (s: string) => string;\n title: (s: string) => string;\n dim: (s: string) => string;\n\n // Semantic colors for screen reader output\n roleName: (s: string) => string;\n stateName: (s: string) => string;\n elementName: (s: string) => string;\n sectionHeader: (s: string) => string;\n description: (s: string) => string;\n\n // Utility\n bold: (s: string) => string;\n enabled: boolean;\n}\n\nconst identity = (s: string): string => s;\n\n/** Check if color output should be enabled for a given stream */\nexport function isColorEnabled(stream: { isTTY?: boolean }): boolean {\n return stream.isTTY === true;\n}\n\n/** Create a set of color functions, either active or passthrough */\nexport function createColors(enabled: boolean): ColorFunctions {\n if (!enabled) {\n return {\n error: identity,\n warning: identity,\n info: identity,\n success: identity,\n heading: identity,\n title: identity,\n dim: identity,\n roleName: identity,\n stateName: identity,\n elementName: identity,\n sectionHeader: identity,\n description: identity,\n bold: identity,\n enabled: false,\n };\n }\n\n return {\n error: pc.red,\n warning: pc.yellow,\n info: pc.blue,\n success: pc.green,\n heading: (s: string) => pc.bold(pc.cyan(s)),\n title: (s: string) => pc.bold(pc.cyan(s)),\n dim: pc.dim,\n roleName: pc.cyan,\n stateName: pc.yellow,\n elementName: (s: string) => pc.bold(pc.white(s)),\n sectionHeader: (s: string) => pc.bold(pc.white(s)),\n description: pc.dim,\n bold: pc.bold,\n enabled: true,\n };\n}\n","/**\n * NVDA screen reader announcement renderer.\n * \n * Generates heuristic announcement text approximating NVDA output.\n * This is NOT a perfect emulation - real NVDA behavior varies by version,\n * settings, and context. Use for development guidance only.\n */\n\nimport type { AccessibleNode, AnnouncementModel } from '../model/types.js';\nimport { createColors, type ColorFunctions } from '../cli/colors.js';\n\n/**\n * Renders an announcement model as NVDA-style announcement text.\n * \n * @param model - Announcement model to render\n * @param colorize - Whether to apply ANSI color codes to the output\n * @returns NVDA-style announcement text\n */\nexport function renderNVDA(model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const announcements: string[] = [];\n renderNodeNVDA(model.root, announcements, c);\n return announcements.join('\\n');\n}\n\n/**\n * Recursively renders a node and its children as NVDA announcements.\n * \n * @param node - Node to render\n * @param announcements - Array to collect announcement strings\n * @param c - Color functions for formatting\n */\nfunction renderNodeNVDA(node: AccessibleNode, announcements: string[], c: ColorFunctions): void {\n const announcement = formatNodeNVDA(node, c);\n if (announcement) {\n announcements.push(announcement);\n }\n \n // Recursively render children, collapsing redundant same-name children\n for (const child of node.children) {\n if (child.name && child.name === node.name && node.children.length === 1) {\n // Skip child that repeats parent name — recurse into grandchildren\n for (const grandchild of child.children) {\n renderNodeNVDA(grandchild, announcements, c);\n }\n continue;\n }\n renderNodeNVDA(child, announcements, c);\n }\n}\n\n/**\n * Formats a single node as an NVDA announcement.\n * \n * @param node - Node to format\n * @param c - Color functions for formatting\n * @returns Formatted announcement string or empty string if node should not be announced\n */\nfunction formatNodeNVDA(node: AccessibleNode, c: ColorFunctions): string {\n const parts: string[] = [];\n \n // Add name (if present)\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n \n // Add role-specific formatting\n const roleText = formatRoleNVDA(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n \n // Add states\n const stateText = formatStatesNVDA(node);\n if (stateText) {\n parts.push(c.stateName(stateText));\n }\n \n // Add value (for form controls)\n if (node.value) {\n const valueText = node.value.text || String(node.value.current);\n if (valueText) {\n parts.push(valueText);\n }\n }\n \n // Add description (if present)\n if (node.description) {\n parts.push(c.description(node.description));\n }\n \n return parts.join(', ');\n}\n\n/**\n * Formats the role portion of an NVDA announcement.\n * \n * @param node - Node to format\n * @returns Role text or empty string\n */\nfunction formatRoleNVDA(node: AccessibleNode): string {\n const role = node.role;\n \n switch (role) {\n case 'button':\n return 'button';\n \n case 'link':\n return 'link';\n \n case 'heading':\n if (node.state.level) {\n return `heading level ${node.state.level}`;\n }\n return 'heading';\n \n case 'textbox':\n return 'edit';\n \n case 'checkbox':\n return 'checkbox';\n \n case 'radio':\n return 'radio button';\n \n case 'combobox':\n return 'combo box';\n \n case 'listbox':\n return 'list box';\n \n case 'option':\n return 'option';\n \n case 'list':\n return 'list';\n \n case 'listitem':\n return 'list item';\n \n case 'navigation':\n return 'navigation landmark';\n \n case 'main':\n return 'main landmark';\n \n case 'banner':\n return 'banner landmark';\n \n case 'contentinfo':\n return 'content information landmark';\n \n case 'region':\n return 'region landmark';\n \n case 'complementary':\n return 'complementary landmark';\n \n case 'form':\n return 'form landmark';\n \n case 'search':\n return 'search landmark';\n \n case 'img':\n return 'graphic';\n \n case 'article':\n return 'article';\n \n case 'generic':\n // Generic containers are typically not announced\n return '';\n \n case 'staticText':\n case 'paragraph':\n case 'cell':\n case 'term':\n case 'definition':\n case 'caption':\n return '';\n \n case 'blockquote':\n return 'block quote';\n \n case 'code':\n return 'code';\n \n case 'table':\n return 'table';\n \n case 'row':\n return 'row';\n \n case 'columnheader':\n return 'column header';\n \n case 'rowheader':\n return 'row header';\n \n case 'figure':\n return 'figure';\n \n case 'dialog':\n return 'dialog';\n \n case 'meter':\n return 'meter';\n \n case 'progressbar':\n return 'progress bar';\n \n case 'status':\n return 'status';\n \n case 'group':\n return node.name ? 'grouping' : '';\n \n case 'document':\n return 'document';\n \n case 'application':\n return 'embedded object';\n \n case 'separator':\n return 'separator';\n \n default:\n return role;\n }\n}\n\n/**\n * Formats the state portion of an NVDA announcement.\n * \n * @param node - Node to format\n * @returns State text or empty string\n */\nfunction formatStatesNVDA(node: AccessibleNode): string {\n const states: string[] = [];\n \n // Expanded/collapsed state\n if (node.state.expanded !== undefined) {\n states.push(node.state.expanded ? 'expanded' : 'collapsed');\n }\n \n // Checked state (checkbox/radio)\n if (node.state.checked !== undefined) {\n if (node.state.checked === 'mixed') {\n states.push('half checked');\n } else {\n states.push(node.state.checked ? 'checked' : 'not checked');\n }\n }\n \n // Pressed state (toggle button)\n if (node.state.pressed !== undefined) {\n if (node.state.pressed === 'mixed') {\n states.push('half pressed');\n } else {\n states.push(node.state.pressed ? 'pressed' : 'not pressed');\n }\n }\n \n // Selected state\n if (node.state.selected !== undefined) {\n states.push(node.state.selected ? 'selected' : 'not selected');\n }\n \n // Disabled state\n if (node.state.disabled) {\n states.push('unavailable');\n }\n \n // Invalid state\n if (node.state.invalid) {\n states.push('invalid entry');\n }\n \n // Required state\n if (node.state.required) {\n states.push('required');\n }\n \n // Read-only state\n if (node.state.readonly) {\n states.push('read only');\n }\n \n // Busy state\n if (node.state.busy) {\n states.push('busy');\n }\n \n // Current state\n if (node.state.current) {\n if (node.state.current === 'page') {\n states.push('current page');\n } else if (node.state.current === 'step') {\n states.push('current step');\n } else if (node.state.current === 'location') {\n states.push('current location');\n } else if (node.state.current === 'date') {\n states.push('current date');\n } else if (node.state.current === 'time') {\n states.push('current time');\n } else if (node.state.current === 'true') {\n states.push('current');\n }\n }\n \n // Grabbed state (drag and drop)\n if (node.state.grabbed !== undefined) {\n states.push(node.state.grabbed ? 'grabbed' : 'not grabbed');\n }\n \n return states.join(', ');\n}\n","/**\n * JAWS screen reader announcement renderer.\n * \n * Generates heuristic announcement text approximating JAWS output.\n * This is NOT a perfect emulation - real JAWS behavior varies by version,\n * settings, verbosity level, and context. Use for development guidance only.\n */\n\nimport type { AccessibleNode, AnnouncementModel } from '../model/types.js';\nimport { createColors, type ColorFunctions } from '../cli/colors.js';\n\n/**\n * Renders an announcement model as JAWS-style announcement text.\n * \n * @param model - Announcement model to render\n * @param colorize - Whether to apply ANSI color codes to the output\n * @returns JAWS-style announcement text\n */\nexport function renderJAWS(model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const announcements: string[] = [];\n renderNodeJAWS(model.root, announcements, c);\n return announcements.join('\\n');\n}\n\n/**\n * Recursively renders a node and its children as JAWS announcements.\n * \n * @param node - Node to render\n * @param announcements - Array to collect announcement strings\n * @param c - Color functions for formatting\n */\nfunction renderNodeJAWS(node: AccessibleNode, announcements: string[], c: ColorFunctions): void {\n const announcement = formatNodeJAWS(node, c);\n if (announcement) {\n announcements.push(announcement);\n }\n \n // Recursively render children, collapsing redundant same-name children\n for (const child of node.children) {\n if (child.name && child.name === node.name && node.children.length === 1) {\n for (const grandchild of child.children) {\n renderNodeJAWS(grandchild, announcements, c);\n }\n continue;\n }\n renderNodeJAWS(child, announcements, c);\n }\n}\n\n/**\n * Formats a single node as a JAWS announcement.\n * \n * @param node - Node to format\n * @param c - Color functions for formatting\n * @returns Formatted announcement string or empty string if node should not be announced\n */\nfunction formatNodeJAWS(node: AccessibleNode, c: ColorFunctions): string {\n const parts: string[] = [];\n \n // Add name (if present)\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n \n // Add role-specific formatting\n const roleText = formatRoleJAWS(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n \n // Add states\n const stateText = formatStatesJAWS(node);\n if (stateText) {\n parts.push(c.stateName(stateText));\n }\n \n // Add value (for form controls)\n if (node.value) {\n const valueText = node.value.text || String(node.value.current);\n if (valueText) {\n parts.push(valueText);\n }\n }\n \n // Add description (if present)\n if (node.description) {\n parts.push(c.description(node.description));\n }\n \n return parts.join(', ');\n}\n\n/**\n * Formats the role portion of a JAWS announcement.\n * \n * @param node - Node to format\n * @returns Role text or empty string\n */\nfunction formatRoleJAWS(node: AccessibleNode): string {\n const role = node.role;\n \n switch (role) {\n case 'button':\n return 'button';\n \n case 'link':\n // JAWS uses \"clickable\" for links\n return 'clickable';\n \n case 'heading':\n if (node.state.level) {\n return `heading ${node.state.level}`;\n }\n return 'heading';\n \n case 'textbox':\n return 'edit';\n \n case 'checkbox':\n return 'check box';\n \n case 'radio':\n return 'radio button';\n \n case 'combobox':\n // JAWS uses \"combo box\" (two words)\n return 'combo box';\n \n case 'listbox':\n return 'list box';\n \n case 'option':\n return 'option';\n \n case 'list':\n return 'list';\n \n case 'listitem':\n return 'list item';\n \n case 'navigation':\n return 'navigation region';\n \n case 'main':\n return 'main region';\n \n case 'banner':\n return 'banner region';\n \n case 'contentinfo':\n return 'content information region';\n \n case 'region':\n return 'region';\n \n case 'img':\n return 'graphic';\n \n case 'article':\n return 'article';\n \n case 'complementary':\n return 'complementary region';\n \n case 'form':\n return 'form';\n \n case 'search':\n return 'search region';\n \n case 'generic':\n // Generic containers typically not announced\n return '';\n \n case 'staticText':\n case 'paragraph':\n case 'term':\n case 'definition':\n case 'caption':\n return '';\n \n case 'blockquote':\n return 'block quote';\n \n case 'code':\n return 'code';\n \n case 'table': {\n const rows = node.children.filter(c => c.role === 'row');\n const rowCount = rows.length;\n const colCount = rows.length > 0 ? rows[0].children.length : 0;\n return `table with ${rowCount} rows and ${colCount} columns`;\n }\n \n case 'row': {\n const pos = node.state.posinset ?? 0;\n return `row ${pos}`;\n }\n \n case 'cell': {\n const pos = node.state.posinset ?? 0;\n return `column ${pos}`;\n }\n \n case 'columnheader':\n return 'column header';\n \n case 'rowheader':\n return 'row header';\n \n case 'figure':\n return 'figure';\n \n case 'dialog':\n return 'dialog';\n \n case 'meter':\n return 'meter';\n \n case 'progressbar':\n return 'progress bar';\n \n case 'status':\n return 'status';\n \n case 'group':\n return node.name ? 'group' : '';\n \n case 'document':\n return 'frame';\n \n case 'application':\n return 'embedded object';\n \n case 'separator':\n return 'separator';\n \n default:\n return role;\n }\n}\n\n/**\n * Formats the state portion of a JAWS announcement.\n * \n * @param node - Node to format\n * @returns State text or empty string\n */\nfunction formatStatesJAWS(node: AccessibleNode): string {\n const states: string[] = [];\n \n // Expanded/collapsed\n if (node.state.expanded !== undefined) {\n states.push(node.state.expanded ? 'expanded' : 'collapsed');\n }\n \n // Checked state (checkbox, radio)\n if (node.state.checked !== undefined) {\n if (node.state.checked === 'mixed') {\n states.push('partially checked');\n } else if (node.state.checked) {\n states.push('checked');\n } else {\n states.push('not checked');\n }\n }\n \n // Pressed state (toggle button)\n if (node.state.pressed !== undefined) {\n if (node.state.pressed === 'mixed') {\n states.push('partially pressed');\n } else if (node.state.pressed) {\n states.push('pressed');\n } else {\n states.push('not pressed');\n }\n }\n \n // Selected state\n if (node.state.selected !== undefined) {\n states.push(node.state.selected ? 'selected' : 'not selected');\n }\n \n // Disabled state\n if (node.state.disabled) {\n states.push('unavailable');\n }\n \n // Invalid state\n if (node.state.invalid) {\n states.push('invalid entry');\n }\n \n // Required state\n if (node.state.required) {\n states.push('required');\n }\n \n // Read-only state\n if (node.state.readonly) {\n states.push('read only');\n }\n \n // Busy state\n if (node.state.busy) {\n states.push('busy');\n }\n \n // Current state\n if (node.state.current) {\n switch (node.state.current) {\n case 'page':\n states.push('current page');\n break;\n case 'step':\n states.push('current step');\n break;\n case 'location':\n states.push('current location');\n break;\n case 'date':\n states.push('current date');\n break;\n case 'time':\n states.push('current time');\n break;\n case 'true':\n states.push('current');\n break;\n }\n }\n \n // Grabbed state (drag and drop)\n if (node.state.grabbed !== undefined) {\n states.push(node.state.grabbed ? 'grabbed' : 'not grabbed');\n }\n \n return states.join(', ');\n}\n","/**\n * VoiceOver screen reader announcement renderer.\n * \n * Generates heuristic announcement text approximating VoiceOver output.\n * This is NOT a perfect emulation - real VoiceOver behavior varies by version,\n * settings, and context. Use for development guidance only.\n */\n\nimport type { AccessibleNode, AccessibleRole, AnnouncementModel } from '../model/types.js';\nimport { createColors, type ColorFunctions } from '../cli/colors.js';\n\n/**\n * Renders an announcement model as VoiceOver-style announcement text.\n * \n * @param model - Announcement model to render\n * @param colorize - Whether to apply ANSI color codes to the output\n * @returns VoiceOver-style announcement text\n */\nexport function renderVoiceOver(model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const announcements: string[] = [];\n renderNodeVoiceOver(model.root, announcements, c);\n return announcements.join('\\n');\n}\n\n/**\n * Recursively renders a node and its children as VoiceOver announcements.\n * \n * @param node - Node to render\n * @param announcements - Array to collect announcement strings\n * @param c - Color functions for formatting\n */\nfunction renderNodeVoiceOver(node: AccessibleNode, announcements: string[], c: ColorFunctions): void {\n const announcement = formatNodeVoiceOver(node, c);\n if (announcement) {\n announcements.push(announcement);\n }\n \n // Recursively render children, collapsing redundant same-name children\n for (const child of node.children) {\n if (child.name && child.name === node.name && node.children.length === 1) {\n for (const grandchild of child.children) {\n renderNodeVoiceOver(grandchild, announcements, c);\n }\n continue;\n }\n renderNodeVoiceOver(child, announcements, c);\n }\n}\n\n/**\n * Formats a single node as a VoiceOver announcement.\n * \n * @param node - Node to format\n * @param c - Color functions for formatting\n * @returns Formatted announcement string or empty string if node should not be announced\n */\nfunction formatNodeVoiceOver(node: AccessibleNode, c: ColorFunctions): string {\n const parts: string[] = [];\n \n // VoiceOver often announces role before name for some elements\n const roleFirst = shouldAnnounceRoleFirst(node.role);\n \n if (roleFirst) {\n // Add role first\n const roleText = formatRoleVoiceOver(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n \n // Then name\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n } else {\n // Add name first\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n \n // Then role\n const roleText = formatRoleVoiceOver(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n }\n \n // Add states\n const stateText = formatStatesVoiceOver(node);\n if (stateText) {\n parts.push(c.stateName(stateText));\n }\n \n // Add value (for form controls)\n if (node.value) {\n const valueText = node.value.text || String(node.value.current);\n if (valueText) {\n parts.push(valueText);\n }\n }\n \n // Add description (if present)\n if (node.description) {\n parts.push(c.description(node.description));\n }\n \n return parts.join(', ');\n}\n\n/**\n * Determines if role should be announced before name.\n * \n * VoiceOver announces role first for headings and some landmarks.\n * \n * @param role - Role to check\n * @returns true if role should be announced first\n */\nfunction shouldAnnounceRoleFirst(role: AccessibleRole): boolean {\n return role === 'heading' || \n role === 'navigation' ||\n role === 'main' ||\n role === 'banner' ||\n role === 'contentinfo' ||\n role === 'complementary' ||\n role === 'region' ||\n role === 'form' ||\n role === 'search' ||\n role === 'blockquote' ||\n role === 'figure' ||\n role === 'dialog' ||\n role === 'group' ||\n role === 'document';\n}\n\n/**\n * Formats the role portion of a VoiceOver announcement.\n * \n * @param node - Node to format\n * @returns Role text or empty string\n */\nfunction formatRoleVoiceOver(node: AccessibleNode): string {\n const role = node.role;\n \n switch (role) {\n case 'button':\n return 'button';\n \n case 'link':\n return 'link';\n \n case 'heading':\n if (node.state.level) {\n return `heading level ${node.state.level}`;\n }\n return 'heading';\n \n case 'textbox':\n return 'edit text';\n \n case 'checkbox':\n return 'checkbox';\n \n case 'radio':\n return 'radio button';\n \n case 'combobox':\n return 'combo box';\n \n case 'listbox':\n return 'list box';\n \n case 'option':\n return 'option';\n \n case 'list':\n return 'list';\n \n case 'listitem':\n return 'item';\n \n case 'navigation':\n return 'navigation';\n \n case 'main':\n return 'main';\n \n case 'banner':\n return 'banner';\n \n case 'contentinfo':\n return 'content information';\n \n case 'region':\n return 'region';\n \n case 'complementary':\n return 'complementary';\n \n case 'form':\n return 'form';\n \n case 'search':\n return 'search';\n \n case 'img':\n return 'image';\n \n case 'article':\n return 'article';\n \n case 'generic':\n // Generic containers are typically not announced\n return '';\n \n case 'staticText':\n case 'paragraph':\n case 'cell':\n case 'term':\n case 'definition':\n case 'caption':\n return '';\n \n case 'blockquote':\n return 'blockquote';\n \n case 'code':\n return 'code';\n \n case 'table': {\n const rows = node.children.filter(c => c.role === 'row');\n const rowCount = rows.length;\n const colCount = rows.length > 0 ? rows[0].children.length : 0;\n return `table, ${rowCount} rows, ${colCount} columns`;\n }\n \n case 'row':\n return 'row';\n \n case 'columnheader':\n return 'column header';\n \n case 'rowheader':\n return 'row header';\n \n case 'figure':\n return 'figure';\n \n case 'dialog':\n return 'web dialog';\n \n case 'meter':\n return 'level indicator';\n \n case 'progressbar':\n return 'progress indicator';\n \n case 'status':\n return 'status';\n \n case 'group':\n return node.name ? 'group' : '';\n \n case 'document':\n return 'frame';\n \n case 'application':\n return 'embedded object';\n \n case 'separator':\n return 'separator';\n \n default:\n return role;\n }\n}\n\n/**\n * Formats the state portion of a VoiceOver announcement.\n * \n * @param node - Node to format\n * @returns State text or empty string\n */\nfunction formatStatesVoiceOver(node: AccessibleNode): string {\n const states: string[] = [];\n \n // Expanded/collapsed state\n if (node.state.expanded !== undefined) {\n states.push(node.state.expanded ? 'expanded' : 'collapsed');\n }\n \n // Checked state (checkbox/radio)\n if (node.state.checked !== undefined) {\n if (node.state.checked === 'mixed') {\n states.push('mixed');\n } else {\n states.push(node.state.checked ? 'checked' : 'unchecked');\n }\n }\n \n // Pressed state (toggle button)\n if (node.state.pressed !== undefined) {\n if (node.state.pressed === 'mixed') {\n states.push('mixed');\n } else {\n states.push(node.state.pressed ? 'pressed' : 'not pressed');\n }\n }\n \n // Selected state\n if (node.state.selected !== undefined) {\n states.push(node.state.selected ? 'selected' : 'unselected');\n }\n \n // Disabled state\n if (node.state.disabled) {\n states.push('dimmed');\n }\n \n // Invalid state\n if (node.state.invalid) {\n states.push('invalid data');\n }\n \n // Required state\n if (node.state.required) {\n states.push('required');\n }\n \n // Read-only state\n if (node.state.readonly) {\n states.push('read only');\n }\n \n // Busy state\n if (node.state.busy) {\n states.push('busy');\n }\n \n // Current state\n if (node.state.current) {\n if (node.state.current === 'page') {\n states.push('current page');\n } else if (node.state.current === 'step') {\n states.push('current step');\n } else if (node.state.current === 'location') {\n states.push('current location');\n } else if (node.state.current === 'date') {\n states.push('current date');\n } else if (node.state.current === 'time') {\n states.push('current time');\n } else if (node.state.current === 'true') {\n states.push('current');\n }\n }\n \n // Grabbed state (drag and drop)\n if (node.state.grabbed !== undefined) {\n states.push(node.state.grabbed ? 'grabbed' : 'not grabbed');\n }\n \n return states.join(', ');\n}\n","/**\n * Windows Narrator screen reader announcement renderer.\n * \n * Generates heuristic announcement text approximating Windows Narrator output.\n * This is NOT a perfect emulation - real Narrator behavior varies by version,\n * settings, and context. Use for development guidance only.\n */\n\nimport type { AccessibleNode, AccessibleRole, AnnouncementModel } from '../model/types.js';\nimport { createColors, type ColorFunctions } from '../cli/colors.js';\n\n/**\n * Renders an announcement model as Narrator-style announcement text.\n * \n * @param model - Announcement model to render\n * @param colorize - Whether to apply ANSI color codes to the output\n * @returns Narrator-style announcement text\n */\nexport function renderNarrator(model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const announcements: string[] = [];\n renderNodeNarrator(model.root, announcements, c);\n return announcements.join('\\n');\n}\n\n/**\n * Recursively renders a node and its children as Narrator announcements.\n * \n * @param node - Node to render\n * @param announcements - Array to collect announcement strings\n * @param c - Color functions for formatting\n */\nfunction renderNodeNarrator(node: AccessibleNode, announcements: string[], c: ColorFunctions): void {\n const announcement = formatNodeNarrator(node, c);\n if (announcement) {\n announcements.push(announcement);\n }\n\n // Recursively render children, collapsing redundant same-name children\n for (const child of node.children) {\n if (child.name && child.name === node.name && node.children.length === 1) {\n // Skip child that repeats parent name — recurse into grandchildren\n for (const grandchild of child.children) {\n renderNodeNarrator(grandchild, announcements, c);\n }\n continue;\n }\n renderNodeNarrator(child, announcements, c);\n }\n}\n\n/**\n * Formats a single node as a Narrator announcement.\n * \n * @param node - Node to format\n * @param c - Color functions for formatting\n * @returns Formatted announcement string or empty string if node should not be announced\n */\nfunction formatNodeNarrator(node: AccessibleNode, c: ColorFunctions): string {\n const parts: string[] = [];\n\n const roleFirst = shouldAnnounceRoleFirst(node.role);\n\n if (roleFirst) {\n // Role-first: role, name, state, value, description\n const roleText = formatRoleNarrator(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n } else {\n // Name-first: name, role, state, value, description\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n\n const roleText = formatRoleNarrator(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n }\n\n // Add states\n const stateText = formatStatesNarrator(node);\n if (stateText) {\n parts.push(c.stateName(stateText));\n }\n\n // Add value (for form controls)\n if (node.value) {\n const valueText = node.value.text || String(node.value.current);\n if (valueText) {\n parts.push(valueText);\n }\n }\n\n // Add description (if present)\n if (node.description) {\n parts.push(c.description(node.description));\n }\n\n return parts.join(', ');\n}\n\n/**\n * Determines if role should be announced before name.\n * \n * Narrator announces role first for links, headings, landmarks,\n * and structural containers.\n * \n * @param role - Role to check\n * @returns true if role should be announced first\n */\nfunction shouldAnnounceRoleFirst(role: AccessibleRole): boolean {\n const roleFirstRoles: AccessibleRole[] = [\n 'link',\n 'heading',\n 'navigation',\n 'main',\n 'banner',\n 'contentinfo',\n 'complementary',\n 'region',\n 'form',\n 'search',\n 'blockquote',\n 'figure',\n 'dialog',\n 'group',\n 'document',\n ];\n return roleFirstRoles.includes(role);\n}\n\n/**\n * Formats the role portion of a Narrator announcement.\n * \n * @param node - Node to format\n * @returns Role text or empty string\n */\nfunction formatRoleNarrator(node: AccessibleNode): string {\n const role = node.role;\n\n switch (role) {\n case 'button':\n return 'button';\n\n case 'link':\n return 'link';\n\n case 'heading':\n if (node.state.level) {\n return `Heading level ${node.state.level}`;\n }\n return 'Heading';\n\n case 'textbox':\n return 'edit';\n\n case 'checkbox':\n return 'check box';\n\n case 'radio':\n return 'radio button';\n\n case 'combobox':\n return 'combo box';\n\n case 'listbox':\n return 'list box';\n\n case 'option':\n return 'option';\n\n case 'list':\n return 'list';\n\n case 'listitem':\n return 'list item';\n\n case 'navigation':\n return 'navigation';\n\n case 'main':\n return 'main';\n\n case 'banner':\n return 'banner';\n\n case 'contentinfo':\n return 'content info';\n\n case 'complementary':\n return 'complementary';\n\n case 'form':\n return 'form';\n\n case 'search':\n return 'search';\n\n case 'region':\n return 'region';\n\n case 'img':\n return 'image';\n\n case 'article':\n return 'article';\n\n case 'generic':\n return '';\n\n case 'staticText':\n case 'paragraph':\n case 'cell':\n case 'term':\n case 'definition':\n case 'caption':\n return '';\n\n case 'blockquote':\n return 'block quote';\n\n case 'code':\n return 'code';\n\n case 'table': {\n const rows = node.children.filter(c => c.role === 'row');\n const rowCount = rows.length;\n const colCount = rows.length > 0 ? rows[0].children.length : 0;\n return `table, ${rowCount} rows, ${colCount} columns`;\n }\n\n case 'row':\n return 'row';\n\n case 'columnheader':\n return 'column header';\n\n case 'rowheader':\n return 'row header';\n\n case 'figure':\n return 'figure';\n\n case 'dialog':\n return 'dialog';\n\n case 'meter':\n return 'meter';\n\n case 'progressbar':\n return 'progress bar';\n\n case 'status':\n return 'status';\n\n case 'group':\n return node.name ? 'group' : '';\n\n case 'document':\n return 'document';\n\n case 'application':\n return 'application';\n\n case 'separator':\n return 'separator';\n\n default:\n return role;\n }\n}\n\n/**\n * Formats the state portion of a Narrator announcement.\n * \n * @param node - Node to format\n * @returns State text or empty string\n */\nfunction formatStatesNarrator(node: AccessibleNode): string {\n const states: string[] = [];\n\n // Expanded/collapsed state\n if (node.state.expanded !== undefined) {\n states.push(node.state.expanded ? 'expanded' : 'collapsed');\n }\n\n // Checked state (checkbox/radio)\n if (node.state.checked !== undefined) {\n if (node.state.checked === 'mixed') {\n states.push('partially selected');\n } else {\n states.push(node.state.checked ? 'checked' : 'unchecked');\n }\n }\n\n // Pressed state (toggle button)\n if (node.state.pressed !== undefined) {\n if (node.state.pressed === 'mixed') {\n states.push('partially pressed');\n } else {\n states.push(node.state.pressed ? 'pressed' : 'not pressed');\n }\n }\n\n // Selected state\n if (node.state.selected !== undefined) {\n states.push(node.state.selected ? 'selected' : 'not selected');\n }\n\n // Disabled state\n if (node.state.disabled) {\n states.push('disabled');\n }\n\n // Invalid state\n if (node.state.invalid) {\n states.push('invalid');\n }\n\n // Required state\n if (node.state.required) {\n states.push('required');\n }\n\n // Read-only state\n if (node.state.readonly) {\n states.push('read only');\n }\n\n // Busy state\n if (node.state.busy) {\n states.push('busy');\n }\n\n // Current state\n if (node.state.current) {\n if (node.state.current === 'page') {\n states.push('current page');\n } else if (node.state.current === 'step') {\n states.push('current step');\n } else if (node.state.current === 'location') {\n states.push('current location');\n } else if (node.state.current === 'date') {\n states.push('current date');\n } else if (node.state.current === 'time') {\n states.push('current time');\n } else if (node.state.current === 'true') {\n states.push('current');\n }\n }\n\n // Grabbed state (drag and drop)\n if (node.state.grabbed !== undefined) {\n states.push(node.state.grabbed ? 'grabbed' : 'not grabbed');\n }\n\n return states.join(', ');\n}\n","/**\n * Developer-friendly audit report renderer.\n * \n * Generates human-readable accessibility audit reports with:\n * - Landmark structure analysis\n * - Heading hierarchy validation\n * - Interactive element inventory\n * - Common accessibility issue detection\n * - Summary statistics\n */\n\nimport type { AccessibleNode, AccessibleRole, AnnouncementModel } from '../model/types.js';\nimport { createColors } from '../cli/colors.js';\n\n/**\n * Severity level for accessibility issues.\n */\nexport type IssueSeverity = 'error' | 'warning' | 'info';\n\n/**\n * Accessibility issue detected during audit.\n */\nexport interface AccessibilityIssue {\n severity: IssueSeverity;\n message: string;\n suggestion?: string;\n element?: {\n role: AccessibleRole;\n name: string;\n };\n}\n\n/**\n * Audit report statistics.\n */\nexport interface AuditStatistics {\n totalElements: number;\n roleDistribution: Record<string, number>;\n landmarkCount: number;\n headingCount: number;\n interactiveCount: number;\n focusableCount: number;\n statesUsed: Set<string>;\n}\n\n/**\n * Complete audit report.\n */\nexport interface AuditReport {\n statistics: AuditStatistics;\n landmarks: AccessibleNode[];\n headings: AccessibleNode[];\n interactiveElements: AccessibleNode[];\n issues: AccessibilityIssue[];\n}\n\n/**\n * Renders an announcement model as a developer-friendly audit report.\n * \n * @param model - Announcement model to audit\n * @returns Formatted audit report text\n */\nexport function renderAuditReport(model: AnnouncementModel, colorize?: boolean): string {\n const report = generateAuditReport(model);\n return formatAuditReport(report, model, colorize);\n}\n\n/**\n * Generates audit report data from an announcement model.\n * \n * @param model - Announcement model to analyze\n * @returns Audit report data\n */\nexport function generateAuditReport(model: AnnouncementModel): AuditReport {\n const statistics: AuditStatistics = {\n totalElements: 0,\n roleDistribution: {},\n landmarkCount: 0,\n headingCount: 0,\n interactiveCount: 0,\n focusableCount: 0,\n statesUsed: new Set(),\n };\n \n const landmarks: AccessibleNode[] = [];\n const headings: AccessibleNode[] = [];\n const interactiveElements: AccessibleNode[] = [];\n const issues: AccessibilityIssue[] = [];\n \n // Collect data from tree\n collectAuditData(model.root, statistics, landmarks, headings, interactiveElements);\n \n // Detect issues\n detectLandmarkIssues(landmarks, issues);\n detectHeadingIssues(headings, issues);\n detectInteractiveIssues(interactiveElements, issues);\n \n return {\n statistics,\n landmarks,\n headings,\n interactiveElements,\n issues,\n };\n}\n\n/**\n * Recursively collects audit data from the accessibility tree.\n */\nfunction collectAuditData(\n node: AccessibleNode,\n statistics: AuditStatistics,\n landmarks: AccessibleNode[],\n headings: AccessibleNode[],\n interactiveElements: AccessibleNode[]\n): void {\n // Skip generic containers in statistics\n if (node.role !== 'generic') {\n statistics.totalElements++;\n \n // Update role distribution\n statistics.roleDistribution[node.role] = (statistics.roleDistribution[node.role] || 0) + 1;\n \n // Collect landmarks\n if (isLandmark(node.role)) {\n statistics.landmarkCount++;\n landmarks.push(node);\n }\n \n // Collect headings\n if (node.role === 'heading') {\n statistics.headingCount++;\n headings.push(node);\n }\n \n // Collect interactive elements\n if (isInteractive(node.role)) {\n statistics.interactiveCount++;\n interactiveElements.push(node);\n }\n \n // Count focusable elements\n if (node.focus.focusable) {\n statistics.focusableCount++;\n }\n \n // Collect states used\n Object.keys(node.state).forEach(state => {\n if (node.state[state as keyof typeof node.state] !== undefined) {\n statistics.statesUsed.add(state);\n }\n });\n }\n \n // Recurse through children\n for (const child of node.children) {\n collectAuditData(child, statistics, landmarks, headings, interactiveElements);\n }\n}\n\n/**\n * Checks if a role is a landmark.\n */\nfunction isLandmark(role: AccessibleRole): boolean {\n return [\n 'navigation',\n 'main',\n 'banner',\n 'contentinfo',\n 'region',\n 'complementary',\n 'form',\n 'search',\n ].includes(role);\n}\n\n/**\n * Checks if a role is interactive.\n */\nfunction isInteractive(role: AccessibleRole): boolean {\n return [\n 'button',\n 'link',\n 'textbox',\n 'checkbox',\n 'radio',\n 'combobox',\n 'listbox',\n 'option',\n ].includes(role);\n}\n\n/**\n * Detects issues with landmarks.\n */\nfunction detectLandmarkIssues(landmarks: AccessibleNode[], issues: AccessibilityIssue[]): void {\n if (landmarks.length === 0) {\n issues.push({\n severity: 'info',\n message: 'No landmarks found',\n suggestion: 'Consider adding semantic landmarks (main, nav, aside, etc.)',\n });\n }\n \n // Check for unnamed landmarks\n landmarks.forEach(landmark => {\n if (!landmark.name && ['navigation', 'region', 'complementary', 'form'].includes(landmark.role)) {\n issues.push({\n severity: 'warning',\n message: `${landmark.role} landmark has no accessible name`,\n suggestion: `Add aria-label=\"${landmark.role === 'navigation' ? 'Main navigation' : 'Descriptive name'}\" to the ${landmark.role} element`,\n element: {\n role: landmark.role,\n name: landmark.name,\n },\n });\n }\n });\n \n // Check for duplicate landmark roles without distinguishing names\n const landmarksByRole = new Map<string, AccessibleNode[]>();\n landmarks.forEach(landmark => {\n if (!landmarksByRole.has(landmark.role)) {\n landmarksByRole.set(landmark.role, []);\n }\n landmarksByRole.get(landmark.role)!.push(landmark);\n });\n \n landmarksByRole.forEach((nodes, role) => {\n if (nodes.length > 1) {\n const allUnnamed = nodes.every(n => !n.name);\n const allSameName = nodes.every(n => n.name === nodes[0].name);\n \n if (allUnnamed || allSameName) {\n issues.push({\n severity: 'warning',\n message: `Multiple ${role} landmarks without distinguishing names`,\n suggestion: `Add unique aria-label attributes to distinguish between ${role} landmarks`,\n });\n }\n }\n });\n}\n\n/**\n * Detects issues with heading hierarchy.\n */\nfunction detectHeadingIssues(headings: AccessibleNode[], issues: AccessibilityIssue[]): void {\n if (headings.length === 0) {\n return;\n }\n \n // Check if first heading is h1\n const firstHeading = headings[0];\n if (firstHeading.state.level && firstHeading.state.level !== 1) {\n issues.push({\n severity: 'error',\n message: `First heading is h${firstHeading.state.level} (should be h1)`,\n suggestion: `Change <h${firstHeading.state.level}> to <h1> or add h1 before it`,\n element: {\n role: firstHeading.role,\n name: firstHeading.name,\n },\n });\n }\n \n // Check for skipped levels\n for (let i = 1; i < headings.length; i++) {\n const prevLevel = headings[i - 1].state.level || 1;\n const currLevel = headings[i].state.level || 1;\n \n if (currLevel > prevLevel + 1) {\n issues.push({\n severity: 'error',\n message: `Heading hierarchy violation: h${prevLevel} followed by h${currLevel} (skipped h${prevLevel + 1})`,\n suggestion: `Change h${currLevel} to h${prevLevel + 1} or add intermediate heading levels`,\n element: {\n role: headings[i].role,\n name: headings[i].name,\n },\n });\n }\n }\n}\n\n/**\n * Detects issues with interactive elements.\n */\nfunction detectInteractiveIssues(elements: AccessibleNode[], issues: AccessibilityIssue[]): void {\n elements.forEach(element => {\n // Check for missing names\n if (!element.name) {\n issues.push({\n severity: 'error',\n message: `${element.role} has no accessible name`,\n suggestion: element.role === 'button' \n ? 'Add text content or aria-label to button'\n : element.role === 'link'\n ? 'Add text content or aria-label to link'\n : `Add aria-label to ${element.role}`,\n element: {\n role: element.role,\n name: element.name,\n },\n });\n }\n \n // Check for form inputs without labels\n if (element.role === 'textbox' && !element.name) {\n issues.push({\n severity: 'error',\n message: 'Input has no associated label',\n suggestion: 'Add <label> element or aria-label attribute',\n element: {\n role: element.role,\n name: element.name,\n },\n });\n }\n });\n}\n\n/**\n * Formats audit report as human-readable text.\n */\nfunction formatAuditReport(report: AuditReport, model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const lines: string[] = [];\n \n // Header\n lines.push(c.title('╔══════════════════════════════════════════════════════════════════════════════╗'));\n lines.push(c.title('║ ACCESSIBILITY AUDIT REPORT ║'));\n lines.push(c.title('╚══════════════════════════════════════════════════════════════════════════════╝'));\n lines.push('');\n lines.push(c.dim(`Analyzed: ${model.metadata.extractedAt}`));\n lines.push('');\n \n // Landmark structure\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('📍 LANDMARK STRUCTURE'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n if (report.landmarks.length === 0) {\n lines.push(c.error('✗ No landmarks found'));\n } else {\n lines.push(c.success(`✓ ${report.landmarks.length} landmark(s) found`));\n lines.push('');\n report.landmarks.forEach(landmark => {\n const name = landmark.name ? `\"${landmark.name}\"` : '(unnamed)';\n lines.push(`${landmark.role} ${name}`);\n });\n }\n lines.push('');\n \n // Heading hierarchy\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('📑 HEADING HIERARCHY'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n if (report.headings.length === 0) {\n lines.push(c.info('ℹ No headings found'));\n } else {\n const hasHierarchyIssues = report.issues.some(i => \n i.message.includes('heading') || i.message.includes('h1') || i.message.includes('h2')\n );\n lines.push(`${hasHierarchyIssues ? c.error('✗') : c.success('✓')} ${report.headings.length} heading(s) found ${hasHierarchyIssues ? '(HIERARCHY VIOLATION)' : '(proper hierarchy)'}`);\n lines.push('');\n \n report.headings.forEach(heading => {\n const level = heading.state.level || 1;\n const indent = ' '.repeat(level - 1);\n lines.push(`${indent}h${level} \"${heading.name}\"`);\n });\n }\n lines.push('');\n \n // Interactive elements\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('🎯 INTERACTIVE ELEMENTS'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n if (report.interactiveElements.length === 0) {\n lines.push(c.info('ℹ No interactive elements found'));\n } else {\n lines.push(c.success(`✓ ${report.interactiveElements.length} interactive element(s) found`));\n lines.push('');\n \n // Group by role\n const byRole = new Map<string, AccessibleNode[]>();\n report.interactiveElements.forEach(el => {\n if (!byRole.has(el.role)) {\n byRole.set(el.role, []);\n }\n byRole.get(el.role)!.push(el);\n });\n \n byRole.forEach((elements, role) => {\n lines.push(`${role}s (${elements.length}):`);\n elements.forEach(el => {\n const name = el.name ? `\"${el.name}\"` : '(unnamed)';\n const states = Object.keys(el.state).filter(k => el.state[k as keyof typeof el.state] !== undefined);\n const stateStr = states.length > 0 ? ` [${states.join(', ')}]` : '';\n lines.push(` • ${name}${stateStr}`);\n });\n });\n }\n lines.push('');\n \n // Summary statistics\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('📊 SUMMARY STATISTICS'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n lines.push(`Total accessible elements: ${report.statistics.totalElements}`);\n lines.push('');\n lines.push('Role distribution:');\n Object.entries(report.statistics.roleDistribution)\n .sort((a, b) => b[1] - a[1])\n .forEach(([role, count]) => {\n lines.push(c.dim(` • ${role}: ${count}`));\n });\n lines.push('');\n lines.push(c.dim(`Focusable elements: ${report.statistics.focusableCount}`));\n lines.push('');\n \n // Issues\n if (report.issues.length > 0) {\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('⚠️ ACCESSIBILITY ISSUES'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n const errors = report.issues.filter(i => i.severity === 'error');\n const warnings = report.issues.filter(i => i.severity === 'warning');\n const infos = report.issues.filter(i => i.severity === 'info');\n \n if (errors.length > 0) {\n lines.push(c.error(`✗ Error (${errors.length}):`));\n errors.forEach(issue => {\n lines.push(c.error(` • ${issue.message}`));\n if (issue.suggestion) {\n lines.push(` → ${issue.suggestion}`);\n }\n });\n lines.push('');\n }\n \n if (warnings.length > 0) {\n lines.push(c.warning(`⚠ Warning (${warnings.length}):`));\n warnings.forEach(issue => {\n lines.push(c.warning(` • ${issue.message}`));\n if (issue.suggestion) {\n lines.push(` → ${issue.suggestion}`);\n }\n });\n lines.push('');\n }\n \n if (infos.length > 0) {\n lines.push(c.info(`ℹ Info (${infos.length}):`));\n infos.forEach(issue => {\n lines.push(c.info(` • ${issue.message}`));\n if (issue.suggestion) {\n lines.push(` → ${issue.suggestion}`);\n }\n });\n lines.push('');\n }\n }\n \n // Overall assessment\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.success('✅ OVERALL ASSESSMENT'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n const errorCount = report.issues.filter(i => i.severity === 'error').length;\n const warningCount = report.issues.filter(i => i.severity === 'warning').length;\n \n if (errorCount === 0 && warningCount === 0) {\n lines.push(c.success('Excellent! No critical issues found.'));\n } else if (errorCount > 0) {\n lines.push(`Critical accessibility issues found:`);\n lines.push(c.error(` ✗ ${errorCount} error(s)`));\n if (warningCount > 0) {\n lines.push(c.warning(` ⚠ ${warningCount} warning(s)`));\n }\n lines.push('');\n lines.push('Recommendation: Address errors before deployment');\n } else {\n lines.push(`Good structure with minor improvements needed:`);\n lines.push(c.warning(` ⚠ ${warningCount} warning(s)`));\n }\n \n return lines.join('\\n');\n}\n","/**\n * HTML parsing using jsdom.\n * \n * Provides lenient parsing with error recovery for malformed HTML.\n */\n\nimport { JSDOM } from 'jsdom';\n\n/**\n * Parsing error class.\n */\nexport class ParsingError extends Error {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = 'ParsingError';\n }\n}\n\n/**\n * Parsing warning.\n */\nexport interface ParsingWarning {\n message: string;\n line?: number;\n column?: number;\n}\n\n/**\n * Result of HTML parsing.\n */\nexport interface ParseResult {\n /** Parsed DOM document */\n document: Document;\n \n /** Warnings encountered during parsing */\n warnings: ParsingWarning[];\n}\n\n/**\n * Maximum input size in bytes (10 MB).\n * Prevents denial-of-service from extremely large inputs.\n */\nconst MAX_INPUT_SIZE = 10 * 1024 * 1024;\n\n/**\n * Parses HTML string into a DOM document.\n * \n * Uses jsdom with lenient parsing mode to handle malformed HTML.\n * Emits warnings for issues but continues processing.\n * \n * @param html - HTML string to parse\n * @returns Parse result with document and warnings\n * @throws ParsingError if parsing fails completely or input exceeds size limit\n */\nexport function parseHTML(html: string): ParseResult {\n const warnings: ParsingWarning[] = [];\n\n // Input size validation\n const inputSize = Buffer.byteLength(html, 'utf-8');\n if (inputSize > MAX_INPUT_SIZE) {\n throw new ParsingError(\n `Input exceeds maximum size of ${MAX_INPUT_SIZE / (1024 * 1024)} MB (received ${(inputSize / (1024 * 1024)).toFixed(1)} MB). ` +\n `Use CSS selectors to analyze specific sections of large documents.`\n );\n }\n\n try {\n // Create JSDOM instance with lenient parsing\n const dom = new JSDOM(html, {\n contentType: 'text/html',\n // Include useful defaults for accessibility tree extraction\n includeNodeLocations: false,\n storageQuota: 0,\n });\n\n const document = dom.window.document;\n\n // Check for parsing errors in the document\n // jsdom doesn't expose parse errors directly, but we can check for common issues\n if (!document.documentElement) {\n warnings.push({\n message: 'Document has no root element. HTML may be severely malformed.',\n });\n }\n\n // Check if body exists (should be created even for empty HTML)\n if (!document.body) {\n warnings.push({\n message: 'Document has no body element. HTML may be malformed.',\n });\n }\n\n return {\n document,\n warnings,\n };\n } catch (error) {\n // jsdom parsing failed completely\n throw new ParsingError(\n `Failed to parse HTML: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Parses HTML and returns just the document (throws on warnings).\n * \n * Convenience function for cases where warnings should be treated as errors.\n * \n * @param html - HTML string to parse\n * @returns Parsed DOM document\n * @throws ParsingError if parsing fails or warnings are present\n */\nexport function parseHTMLStrict(html: string): Document {\n const result = parseHTML(html);\n\n if (result.warnings.length > 0) {\n const warningMessages = result.warnings.map((w) => w.message).join('; ');\n throw new ParsingError(`HTML parsing warnings: ${warningMessages}`);\n }\n\n return result.document;\n}\n\n/**\n * Validates that HTML string is not empty.\n * \n * @param html - HTML string to validate\n * @throws ParsingError if HTML is empty or whitespace-only\n */\nexport function validateHTMLNotEmpty(html: string): void {\n if (!html || html.trim().length === 0) {\n throw new ParsingError('HTML input is empty or contains only whitespace');\n }\n}\n","/**\n * ARIA accessible name computation.\n * \n * Implements the ARIA name computation algorithm following the W3C specification.\n * https://www.w3.org/TR/accname-1.2/\n */\n\n/**\n * Warning emitted during name computation.\n */\nexport interface NameComputationWarning {\n message: string;\n element: Element;\n}\n\n/**\n * Result of name computation.\n */\nexport interface NameComputationResult {\n name: string;\n warnings: NameComputationWarning[];\n}\n\n/**\n * Result of description computation.\n */\nexport interface DescriptionComputationResult {\n description: string;\n warnings: NameComputationWarning[];\n}\n\n/**\n * Computes the accessible name for an element following ARIA specification.\n * \n * Priority order:\n * 1. aria-labelledby (references to other elements)\n * 2. aria-label\n * 3. Native label (for form controls)\n * 4. alt attribute (for images)\n * 5. Text content (for elements that support it)\n * 6. title attribute (fallback)\n * \n * @param element - Element to compute name for\n * @param visited - Set of visited elements (for cycle detection)\n * @returns Computed accessible name and warnings\n */\nexport function computeAccessibleName(\n element: Element,\n visited: Set<Element> = new Set()\n): NameComputationResult {\n const warnings: NameComputationWarning[] = [];\n\n // Detect circular references\n if (visited.has(element)) {\n warnings.push({\n message: 'Circular reference detected in aria-labelledby chain',\n element,\n });\n return { name: '', warnings };\n }\n\n visited.add(element);\n\n // 1. aria-labelledby (highest priority)\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy) {\n const name = computeNameFromLabelledBy(element, labelledBy, visited, warnings);\n // Always return if aria-labelledby is present, even if name is empty\n return { name, warnings };\n }\n\n // 2. aria-label\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return { name: ariaLabel.trim(), warnings };\n }\n\n // 3. Native label (for form controls)\n if (isFormControl(element)) {\n const labelName = computeNameFromLabel(element);\n if (labelName) {\n return { name: labelName, warnings };\n }\n }\n\n // 4. alt attribute (for images)\n if (element.tagName.toLowerCase() === 'img') {\n const alt = element.getAttribute('alt');\n if (alt !== null) {\n return { name: alt.trim(), warnings };\n }\n }\n\n // 5. Text content (for elements that support it)\n if (supportsNameFromContent(element)) {\n const textName = computeNameFromContent(element, visited);\n if (textName) {\n return { name: textName, warnings };\n }\n }\n\n // 6. title attribute (fallback)\n const title = element.getAttribute('title');\n if (title && title.trim()) {\n return { name: title.trim(), warnings };\n }\n\n // No name found\n return { name: '', warnings };\n}\n\n/**\n * Computes name from aria-labelledby attribute.\n * \n * @param element - Element with aria-labelledby\n * @param labelledBy - Space-separated list of IDs\n * @param visited - Set of visited elements\n * @param warnings - Array to collect warnings\n * @returns Computed name or empty string\n */\nfunction computeNameFromLabelledBy(\n element: Element,\n labelledBy: string,\n visited: Set<Element>,\n warnings: NameComputationWarning[]\n): string {\n const document = element.ownerDocument;\n if (!document) {\n return '';\n }\n\n const ids = labelledBy.trim().split(/\\s+/);\n const names: string[] = [];\n\n for (const id of ids) {\n if (!id) continue;\n\n const referencedElement = document.getElementById(id);\n if (!referencedElement) {\n warnings.push({\n message: `aria-labelledby references non-existent ID: ${id}`,\n element,\n });\n continue;\n }\n\n // Recursively compute name for referenced element\n // For labelledby, we want the text content of the referenced element\n const result = computeAccessibleName(referencedElement, new Set(visited));\n warnings.push(...result.warnings);\n \n // If no name was computed, fall back to text content\n const name = result.name || getTextContent(referencedElement);\n if (name) {\n names.push(name);\n }\n }\n\n return names.join(' ').trim();\n}\n\n/**\n * Computes name from associated label element.\n * \n * @param element - Form control element\n * @returns Name from label or empty string\n */\nfunction computeNameFromLabel(element: Element): string {\n const document = element.ownerDocument;\n if (!document) {\n return '';\n }\n\n // Check for explicit label association via id\n const id = element.getAttribute('id');\n if (id) {\n const label = document.querySelector(`label[for=\"${id}\"]`);\n if (label) {\n return getTextContent(label);\n }\n }\n\n // Check for implicit label (element inside label)\n const parentLabel = element.closest('label');\n if (parentLabel) {\n return getTextContent(parentLabel);\n }\n\n return '';\n}\n\n/**\n * Computes name from element's text content.\n * \n * @param element - Element to get text from\n * @param visited - Set of visited elements\n * @returns Text content or empty string\n */\nfunction computeNameFromContent(element: Element, _visited: Set<Element>): string {\n return getTextContent(element);\n}\n\n/**\n * Gets text content from an element, excluding hidden elements.\n * \n * @param element - Element to get text from\n * @returns Trimmed text content\n */\nfunction getTextContent(element: Element): string {\n // Skip hidden elements\n if (element.getAttribute('aria-hidden') === 'true') {\n return '';\n }\n\n let text = '';\n\n for (const node of Array.from(element.childNodes)) {\n if (node.nodeType === 3) { // TEXT_NODE\n text += node.textContent || '';\n } else if (node.nodeType === 1) { // ELEMENT_NODE\n const childElement = node as Element;\n \n // Skip hidden children\n if (childElement.getAttribute('aria-hidden') === 'true') {\n continue;\n }\n\n text += getTextContent(childElement);\n }\n }\n\n return text.trim();\n}\n\n/**\n * Checks if element is a form control.\n * \n * @param element - Element to check\n * @returns true if element is a form control\n */\nfunction isFormControl(element: Element): boolean {\n const tagName = element.tagName.toLowerCase();\n return (\n tagName === 'input' ||\n tagName === 'textarea' ||\n tagName === 'select' ||\n tagName === 'button'\n );\n}\n\n/**\n * Checks if element supports name from content.\n * \n * Elements like buttons, links, and headings get their name from text content.\n * Form inputs do not.\n * \n * @param element - Element to check\n * @returns true if element supports name from content\n */\nfunction supportsNameFromContent(element: Element): boolean {\n const tagName = element.tagName.toLowerCase();\n const role = element.getAttribute('role');\n\n // Elements that support name from content\n const contentElements = [\n 'button',\n 'a',\n 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'summary',\n 'figcaption',\n 'legend',\n 'caption',\n 'th',\n 'td',\n 'li',\n 'dt',\n 'dd',\n ];\n\n if (contentElements.includes(tagName)) {\n return true;\n }\n\n // Roles that support name from content\n const contentRoles = [\n 'button',\n 'link',\n 'heading',\n 'tab',\n 'treeitem',\n 'option',\n 'row',\n 'cell',\n 'columnheader',\n 'rowheader',\n 'tooltip',\n 'menuitem',\n 'menuitemcheckbox',\n 'menuitemradio',\n ];\n\n if (role && contentRoles.includes(role)) {\n return true;\n }\n\n return false;\n}\n\n\n/**\n * Computes the accessible description for an element.\n * \n * Priority order:\n * 1. aria-describedby (references to other elements)\n * 2. title attribute (fallback)\n * \n * @param element - Element to compute description for\n * @returns Computed accessible description and warnings\n */\nexport function computeAccessibleDescription(\n element: Element\n): DescriptionComputationResult {\n const warnings: NameComputationWarning[] = [];\n\n // 1. aria-describedby (highest priority)\n const describedBy = element.getAttribute('aria-describedby');\n if (describedBy) {\n const description = computeDescriptionFromDescribedBy(\n element,\n describedBy,\n warnings\n );\n if (description) {\n return { description, warnings };\n }\n }\n\n // 2. title attribute (fallback)\n const title = element.getAttribute('title');\n if (title && title.trim()) {\n return { description: title.trim(), warnings };\n }\n\n // No description found\n return { description: '', warnings };\n}\n\n/**\n * Computes description from aria-describedby attribute.\n * \n * @param element - Element with aria-describedby\n * @param describedBy - Space-separated list of IDs\n * @param warnings - Array to collect warnings\n * @returns Computed description or empty string\n */\nfunction computeDescriptionFromDescribedBy(\n element: Element,\n describedBy: string,\n warnings: NameComputationWarning[]\n): string {\n const document = element.ownerDocument;\n if (!document) {\n return '';\n }\n\n const ids = describedBy.trim().split(/\\s+/);\n const descriptions: string[] = [];\n\n for (const id of ids) {\n if (!id) continue;\n\n const referencedElement = document.getElementById(id);\n if (!referencedElement) {\n warnings.push({\n message: `aria-describedby references non-existent ID: ${id}`,\n element,\n });\n continue;\n }\n\n // Get text content from referenced element\n const text = getTextContent(referencedElement);\n if (text) {\n descriptions.push(text);\n }\n }\n\n return descriptions.join(' ').trim();\n}\n","/**\n * Role computation and mapping.\n * \n * Maps HTML elements to their implicit ARIA roles and validates explicit roles.\n */\n\nimport type { AccessibleRole } from '../model/types.js';\nimport { SUPPORTED_ROLES } from '../model/types.js';\n\n/**\n * Warning emitted during role computation.\n */\nexport interface RoleComputationWarning {\n message: string;\n element: Element;\n}\n\n/**\n * Result of role computation.\n */\nexport interface RoleComputationResult {\n role: AccessibleRole | null;\n warnings: RoleComputationWarning[];\n}\n\n/**\n * Mapping of HTML elements to their implicit ARIA roles.\n */\nconst IMPLICIT_ROLE_MAP: Record<string, AccessibleRole> = {\n // Interactive elements\n 'button': 'button',\n 'a': 'link', // Only if href attribute present\n \n // Form controls\n 'input': 'textbox', // Default, varies by type\n 'textarea': 'textbox',\n 'select': 'listbox',\n \n // Headings\n 'h1': 'heading',\n 'h2': 'heading',\n 'h3': 'heading',\n 'h4': 'heading',\n 'h5': 'heading',\n 'h6': 'heading',\n \n // Landmarks\n 'nav': 'navigation',\n 'main': 'main',\n 'header': 'banner', // Only if not nested in article/section\n 'footer': 'contentinfo', // Only if not nested in article/section\n 'aside': 'complementary',\n 'form': 'form',\n 'section': 'region', // Only if has accessible name\n \n // Lists\n 'ul': 'list',\n 'ol': 'list',\n 'li': 'listitem',\n \n // Images\n 'img': 'img',\n \n // Articles\n 'article': 'article',\n\n // Static content (new)\n 'p': 'paragraph',\n 'blockquote': 'blockquote',\n 'code': 'code',\n 'pre': 'code',\n\n // Tables (new)\n 'table': 'table',\n 'tr': 'row',\n 'td': 'cell',\n 'th': 'columnheader', // Default; scope=\"row\" handled in computeImplicitRole\n\n // Definition lists (new)\n 'dl': 'list',\n 'dt': 'term',\n 'dd': 'definition',\n\n // Figures (new)\n 'figure': 'figure',\n 'figcaption': 'caption',\n\n // Disclosure (new)\n 'details': 'group',\n 'summary': 'button',\n\n // Dialogs and widgets (new)\n 'dialog': 'dialog',\n 'meter': 'meter',\n 'progress': 'progressbar',\n 'output': 'status',\n\n // Forms (new)\n 'fieldset': 'group',\n 'legend': 'caption',\n\n // Embedded content (new)\n 'iframe': 'document',\n 'video': 'application',\n 'audio': 'application',\n\n // Separators (new)\n 'hr': 'separator',\n\n // Table caption (new)\n 'caption': 'caption',\n};\n\n/**\n * Input type to role mapping.\n */\nconst INPUT_TYPE_ROLE_MAP: Record<string, AccessibleRole> = {\n 'button': 'button',\n 'submit': 'button',\n 'reset': 'button',\n 'checkbox': 'checkbox',\n 'radio': 'radio',\n 'text': 'textbox',\n 'email': 'textbox',\n 'password': 'textbox',\n 'search': 'textbox',\n 'tel': 'textbox',\n 'url': 'textbox',\n 'number': 'textbox',\n};\n\n/**\n * Computes the accessible role for an element.\n * \n * Priority:\n * 1. Explicit role attribute (if valid)\n * 2. Implicit role based on element type\n * 3. null if no role\n * \n * @param element - Element to compute role for\n * @returns Computed role and warnings\n */\nexport function computeRole(element: Element): RoleComputationResult {\n const warnings: RoleComputationWarning[] = [];\n \n // 1. Check for explicit role attribute\n const explicitRole = element.getAttribute('role');\n if (explicitRole) {\n const role = validateAndNormalizeRole(explicitRole, element, warnings);\n if (role) {\n return { role, warnings };\n }\n // If explicit role is invalid, fall through to implicit role\n }\n \n // 2. Compute implicit role\n const implicitRole = computeImplicitRole(element, warnings);\n return { role: implicitRole, warnings };\n}\n\n/**\n * Validates and normalizes an explicit role attribute.\n * \n * @param roleAttr - Role attribute value\n * @param element - Element with the role\n * @param warnings - Array to collect warnings\n * @returns Validated role or null if invalid\n */\nfunction validateAndNormalizeRole(\n roleAttr: string,\n element: Element,\n warnings: RoleComputationWarning[]\n): AccessibleRole | null {\n const role = roleAttr.trim().toLowerCase();\n \n // Check for presentation/none roles (elements should be hidden from a11y tree)\n if (role === 'presentation' || role === 'none') {\n return null;\n }\n \n // Validate against supported roles\n if (SUPPORTED_ROLES.includes(role as AccessibleRole)) {\n return role as AccessibleRole;\n }\n \n // Invalid or unsupported role\n warnings.push({\n message: `Invalid or unsupported role: \"${roleAttr}\". Falling back to implicit role.`,\n element,\n });\n \n return null;\n}\n\n/**\n * Computes the implicit ARIA role for an element.\n * \n * @param element - Element to compute implicit role for\n * @param warnings - Array to collect warnings\n * @returns Implicit role or null\n */\nfunction computeImplicitRole(\n element: Element,\n _warnings: RoleComputationWarning[]\n): AccessibleRole | null {\n const tagName = element.tagName.toLowerCase();\n \n // Special case: input elements vary by type\n if (tagName === 'input') {\n return computeInputRole(element as HTMLInputElement);\n }\n \n // Special case: links only have link role if href present\n if (tagName === 'a') {\n return element.hasAttribute('href') ? 'link' : null;\n }\n \n // Special case: header/footer only landmarks if not nested\n if (tagName === 'header') {\n return isTopLevelLandmark(element) ? 'banner' : null;\n }\n \n if (tagName === 'footer') {\n return isTopLevelLandmark(element) ? 'contentinfo' : null;\n }\n \n // Special case: th elements — scope=\"row\" maps to rowheader\n if (tagName === 'th') {\n const scope = element.getAttribute('scope');\n return scope === 'row' ? 'rowheader' : 'columnheader';\n }\n\n // Special case: section only has region role if it has accessible name\n if (tagName === 'section') {\n // For now, we'll return 'region' - the caller should check if it has a name\n // In a full implementation, we'd check for aria-label or aria-labelledby\n return element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby')\n ? 'region'\n : null;\n }\n \n // Look up in implicit role map\n const implicitRole = IMPLICIT_ROLE_MAP[tagName];\n return implicitRole || null;\n}\n\n/**\n * Computes the role for an input element based on its type.\n * \n * @param input - Input element\n * @returns Role for the input\n */\nfunction computeInputRole(input: HTMLInputElement): AccessibleRole {\n const type = (input.getAttribute('type') || 'text').toLowerCase();\n return INPUT_TYPE_ROLE_MAP[type] || 'textbox';\n}\n\n/**\n * Checks if header/footer is a top-level landmark.\n * \n * Header and footer only have landmark roles (banner/contentinfo) when they\n * are not nested inside article or section elements.\n * \n * @param element - Header or footer element\n * @returns true if top-level landmark\n */\nfunction isTopLevelLandmark(element: Element): boolean {\n let parent = element.parentElement;\n \n while (parent) {\n const tagName = parent.tagName.toLowerCase();\n if (tagName === 'article' || tagName === 'section') {\n return false;\n }\n parent = parent.parentElement;\n }\n \n return true;\n}\n\n/**\n * Checks if an element should be included in the accessibility tree.\n * \n * Elements are excluded if:\n * - They have role=\"presentation\" or role=\"none\"\n * - They have aria-hidden=\"true\"\n * - They have no accessible role\n * \n * @param element - Element to check\n * @returns true if element should be included\n */\nexport function isAccessible(element: Element): boolean {\n // Check aria-hidden\n if (element.getAttribute('aria-hidden') === 'true') {\n return false;\n }\n \n // Check for presentation/none role\n const role = element.getAttribute('role');\n if (role === 'presentation' || role === 'none') {\n return false;\n }\n \n // Element is accessible if it has a role (explicit or implicit)\n const roleResult = computeRole(element);\n return roleResult.role !== null;\n}\n","/**\n * State and property extraction from ARIA attributes.\n * \n * Extracts accessibility states and properties from elements.\n */\n\nimport type { AccessibleState, AccessibleValue } from '../model/types.js';\n\n/**\n * Warning emitted during state extraction.\n */\nexport interface StateExtractionWarning {\n message: string;\n element: Element;\n}\n\n/**\n * Result of state extraction.\n */\nexport interface StateExtractionResult {\n state: AccessibleState;\n warnings: StateExtractionWarning[];\n}\n\n/**\n * Result of value extraction.\n */\nexport interface ValueExtractionResult {\n value: AccessibleValue | undefined;\n warnings: StateExtractionWarning[];\n}\n\n/**\n * Extracts accessibility state from an element.\n * \n * Extracts ARIA state attributes and native element states.\n * \n * @param element - Element to extract state from\n * @returns Extracted state and warnings\n */\nexport function extractState(element: Element): StateExtractionResult {\n const warnings: StateExtractionWarning[] = [];\n const state: AccessibleState = {};\n\n // aria-expanded\n const expanded = extractBooleanAttribute(element, 'aria-expanded', warnings);\n if (expanded !== undefined) {\n state.expanded = expanded;\n }\n\n // aria-checked (boolean or 'mixed')\n const checked = extractTriStateAttribute(element, 'aria-checked', warnings);\n if (checked !== undefined) {\n state.checked = checked;\n }\n\n // aria-pressed (boolean or 'mixed')\n const pressed = extractTriStateAttribute(element, 'aria-pressed', warnings);\n if (pressed !== undefined) {\n state.pressed = pressed;\n }\n\n // aria-selected\n const selected = extractBooleanAttribute(element, 'aria-selected', warnings);\n if (selected !== undefined) {\n state.selected = selected;\n }\n\n // aria-disabled\n const disabled = extractBooleanAttribute(element, 'aria-disabled', warnings);\n if (disabled !== undefined) {\n state.disabled = disabled;\n }\n\n // aria-invalid\n const invalid = extractBooleanAttribute(element, 'aria-invalid', warnings);\n if (invalid !== undefined) {\n state.invalid = invalid;\n }\n\n // aria-required\n const required = extractBooleanAttribute(element, 'aria-required', warnings);\n if (required !== undefined) {\n state.required = required;\n }\n\n // aria-readonly\n const readonly = extractBooleanAttribute(element, 'aria-readonly', warnings);\n if (readonly !== undefined) {\n state.readonly = readonly;\n }\n\n // aria-busy\n const busy = extractBooleanAttribute(element, 'aria-busy', warnings);\n if (busy !== undefined) {\n state.busy = busy;\n }\n\n // aria-current\n const current = extractCurrentAttribute(element, warnings);\n if (current !== undefined) {\n state.current = current;\n }\n\n // aria-grabbed\n const grabbed = extractBooleanAttribute(element, 'aria-grabbed', warnings);\n if (grabbed !== undefined) {\n state.grabbed = grabbed;\n }\n\n // aria-hidden\n const hidden = extractBooleanAttribute(element, 'aria-hidden', warnings);\n if (hidden !== undefined) {\n state.hidden = hidden;\n }\n\n // aria-level (for headings)\n const level = extractLevelAttribute(element, warnings);\n if (level !== undefined) {\n state.level = level;\n }\n\n // aria-posinset and aria-setsize (for lists, tabs, etc.)\n const posinset = extractNumberAttribute(element, 'aria-posinset', warnings);\n if (posinset !== undefined) {\n state.posinset = posinset;\n }\n\n const setsize = extractNumberAttribute(element, 'aria-setsize', warnings);\n if (setsize !== undefined) {\n state.setsize = setsize;\n }\n\n // Extract native element states\n extractNativeStates(element, state, warnings);\n\n return { state, warnings };\n}\n\n/**\n * Extracts value information from form controls.\n * \n * @param element - Element to extract value from\n * @returns Extracted value and warnings\n */\nexport function extractValue(element: Element): ValueExtractionResult {\n const warnings: StateExtractionWarning[] = [];\n\n // Only extract value for form controls\n const tagName = element.tagName.toLowerCase();\n \n if (tagName === 'input') {\n return extractInputValue(element as HTMLInputElement, warnings);\n }\n\n if (tagName === 'textarea') {\n return extractTextareaValue(element as HTMLTextAreaElement, warnings);\n }\n\n if (tagName === 'select') {\n return extractSelectValue(element as HTMLSelectElement, warnings);\n }\n\n // Check for aria-valuenow (for range widgets)\n const valueNow = element.getAttribute('aria-valuenow');\n if (valueNow !== null) {\n const current = parseFloat(valueNow);\n if (!isNaN(current)) {\n const valueMin = element.getAttribute('aria-valuemin');\n const valueMax = element.getAttribute('aria-valuemax');\n const valueText = element.getAttribute('aria-valuetext');\n\n return {\n value: {\n current,\n min: valueMin !== null ? parseFloat(valueMin) : undefined,\n max: valueMax !== null ? parseFloat(valueMax) : undefined,\n text: valueText || undefined,\n },\n warnings,\n };\n }\n }\n\n return { value: undefined, warnings };\n}\n\n/**\n * Extracts boolean ARIA attribute.\n * \n * @param element - Element to extract from\n * @param attrName - Attribute name\n * @param warnings - Array to collect warnings\n * @returns Boolean value or undefined\n */\nfunction extractBooleanAttribute(\n element: Element,\n attrName: string,\n warnings: StateExtractionWarning[]\n): boolean | undefined {\n const value = element.getAttribute(attrName);\n if (value === null) {\n return undefined;\n }\n\n const normalized = value.toLowerCase().trim();\n if (normalized === 'true') {\n return true;\n }\n if (normalized === 'false') {\n return false;\n }\n\n warnings.push({\n message: `Invalid ${attrName} value: \"${value}\". Expected \"true\" or \"false\".`,\n element,\n });\n return undefined;\n}\n\n/**\n * Extracts tri-state ARIA attribute (boolean or 'mixed').\n * \n * @param element - Element to extract from\n * @param attrName - Attribute name\n * @param warnings - Array to collect warnings\n * @returns Boolean, 'mixed', or undefined\n */\nfunction extractTriStateAttribute(\n element: Element,\n attrName: string,\n warnings: StateExtractionWarning[]\n): boolean | 'mixed' | undefined {\n const value = element.getAttribute(attrName);\n if (value === null) {\n return undefined;\n }\n\n const normalized = value.toLowerCase().trim();\n if (normalized === 'true') {\n return true;\n }\n if (normalized === 'false') {\n return false;\n }\n if (normalized === 'mixed') {\n return 'mixed';\n }\n\n warnings.push({\n message: `Invalid ${attrName} value: \"${value}\". Expected \"true\", \"false\", or \"mixed\".`,\n element,\n });\n return undefined;\n}\n\n/**\n * Extracts aria-current attribute.\n * \n * @param element - Element to extract from\n * @param warnings - Array to collect warnings\n * @returns Current value or undefined\n */\nfunction extractCurrentAttribute(\n element: Element,\n warnings: StateExtractionWarning[]\n): 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | false | undefined {\n const value = element.getAttribute('aria-current');\n if (value === null) {\n return undefined;\n }\n\n const normalized = value.toLowerCase().trim();\n const validValues = ['page', 'step', 'location', 'date', 'time', 'true', 'false'];\n\n if (validValues.includes(normalized)) {\n return normalized === 'false' ? false : (normalized as any);\n }\n\n warnings.push({\n message: `Invalid aria-current value: \"${value}\". Expected one of: ${validValues.join(', ')}.`,\n element,\n });\n return undefined;\n}\n\n/**\n * Extracts aria-level attribute for headings.\n * \n * @param element - Element to extract from\n * @param warnings - Array to collect warnings\n * @returns Level (1-6) or undefined\n */\nfunction extractLevelAttribute(\n element: Element,\n warnings: StateExtractionWarning[]\n): number | undefined {\n // Check aria-level attribute\n const ariaLevel = element.getAttribute('aria-level');\n if (ariaLevel !== null) {\n const level = parseInt(ariaLevel, 10);\n if (!isNaN(level) && level >= 1 && level <= 6) {\n return level;\n }\n warnings.push({\n message: `Invalid aria-level value: \"${ariaLevel}\". Expected integer 1-6.`,\n element,\n });\n return undefined;\n }\n\n // Check native heading level\n const tagName = element.tagName.toLowerCase();\n const match = tagName.match(/^h([1-6])$/);\n if (match) {\n return parseInt(match[1], 10);\n }\n\n return undefined;\n}\n\n/**\n * Extracts numeric ARIA attribute.\n * \n * @param element - Element to extract from\n * @param attrName - Attribute name\n * @param warnings - Array to collect warnings\n * @returns Number or undefined\n */\nfunction extractNumberAttribute(\n element: Element,\n attrName: string,\n warnings: StateExtractionWarning[]\n): number | undefined {\n const value = element.getAttribute(attrName);\n if (value === null) {\n return undefined;\n }\n\n const num = parseInt(value, 10);\n if (isNaN(num) || num < 1) {\n warnings.push({\n message: `Invalid ${attrName} value: \"${value}\". Expected positive integer.`,\n element,\n });\n return undefined;\n }\n\n return num;\n}\n\n/**\n * Extracts native element states (checked, disabled, etc.).\n * \n * @param element - Element to extract from\n * @param state - State object to populate\n * @param warnings - Array to collect warnings\n */\nfunction extractNativeStates(\n element: Element,\n state: AccessibleState,\n _warnings: StateExtractionWarning[]\n): void {\n const tagName = element.tagName.toLowerCase();\n\n // Native checked state for checkboxes and radios\n if (tagName === 'input') {\n const input = element as HTMLInputElement;\n const type = input.type.toLowerCase();\n\n if (type === 'checkbox' || type === 'radio') {\n // Only set if not already set by aria-checked\n if (state.checked === undefined) {\n state.checked = input.checked;\n }\n }\n }\n\n // Native disabled state\n if ('disabled' in element) {\n const htmlElement = element as HTMLInputElement | HTMLButtonElement | HTMLSelectElement | HTMLTextAreaElement;\n // Only set if not already set by aria-disabled\n if (state.disabled === undefined && htmlElement.disabled) {\n state.disabled = true;\n }\n }\n\n // Native required state\n if ('required' in element) {\n const htmlElement = element as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n // Only set if not already set by aria-required\n if (state.required === undefined && htmlElement.required) {\n state.required = true;\n }\n }\n\n // Native readonly state\n if ('readOnly' in element) {\n const htmlElement = element as HTMLInputElement | HTMLTextAreaElement;\n // Only set if not already set by aria-readonly\n if (state.readonly === undefined && htmlElement.readOnly) {\n state.readonly = true;\n }\n }\n}\n\n/**\n * Extracts value from input element.\n */\nfunction extractInputValue(\n input: HTMLInputElement,\n warnings: StateExtractionWarning[]\n): ValueExtractionResult {\n const type = input.type.toLowerCase();\n\n // Checkbox and radio use checked state, not value\n if (type === 'checkbox' || type === 'radio') {\n return { value: undefined, warnings };\n }\n\n // Button types don't have meaningful values\n if (type === 'button' || type === 'submit' || type === 'reset') {\n return { value: undefined, warnings };\n }\n\n // Text-like inputs\n const value = input.value;\n if (value) {\n return {\n value: {\n current: value,\n text: value,\n },\n warnings,\n };\n }\n\n return { value: undefined, warnings };\n}\n\n/**\n * Extracts value from textarea element.\n */\nfunction extractTextareaValue(\n textarea: HTMLTextAreaElement,\n warnings: StateExtractionWarning[]\n): ValueExtractionResult {\n const value = textarea.value;\n if (value) {\n return {\n value: {\n current: value,\n text: value,\n },\n warnings,\n };\n }\n\n return { value: undefined, warnings };\n}\n\n/**\n * Extracts value from select element.\n */\nfunction extractSelectValue(\n select: HTMLSelectElement,\n warnings: StateExtractionWarning[]\n): ValueExtractionResult {\n const value = select.value;\n const selectedOption = select.options[select.selectedIndex];\n const text = selectedOption?.textContent || value;\n\n if (value) {\n return {\n value: {\n current: value,\n text,\n },\n warnings,\n };\n }\n\n return { value: undefined, warnings };\n}\n","/**\n * Focus information extraction.\n * \n * Determines focusability and tabindex for elements.\n */\n\nimport type { FocusInfo } from '../model/types.js';\n\n/**\n * Natively focusable element types.\n */\nconst NATIVELY_FOCUSABLE_ELEMENTS = [\n 'a',\n 'button',\n 'input',\n 'select',\n 'textarea',\n 'area',\n 'iframe',\n 'object',\n 'embed',\n 'audio',\n 'video',\n];\n\n/**\n * Extracts focus information from an element.\n * \n * Determines if an element is focusable and extracts explicit tabindex.\n * \n * @param element - Element to extract focus info from\n * @returns Focus information\n */\nexport function extractFocusInfo(element: Element): FocusInfo {\n const tabindexAttr = element.getAttribute('tabindex');\n const tabindex = tabindexAttr !== null ? parseInt(tabindexAttr, 10) : undefined;\n\n // Determine focusability\n const focusable = isFocusable(element, tabindex);\n\n // Only include tabindex if explicitly set\n return {\n focusable,\n ...(tabindexAttr !== null && !isNaN(tabindex!) && { tabindex }),\n };\n}\n\n/**\n * Determines if an element is focusable.\n * \n * An element is focusable if:\n * - It's a natively focusable element (and not disabled)\n * - It has tabindex >= 0\n * - It has tabindex = -1 (programmatically focusable)\n * \n * @param element - Element to check\n * @param tabindex - Parsed tabindex value\n * @returns true if element is focusable\n */\nfunction isFocusable(element: Element, tabindex: number | undefined): boolean {\n const tagName = element.tagName.toLowerCase();\n\n // Check if element is disabled\n if (isDisabled(element)) {\n return false;\n }\n\n // Explicit tabindex makes element focusable (including -1 for programmatic focus)\n if (tabindex !== undefined && !isNaN(tabindex)) {\n return true;\n }\n\n // Check if natively focusable\n if (isNativelyFocusable(element, tagName)) {\n return true;\n }\n\n // Elements with explicit ARIA roles may be focusable\n // For now, we'll be conservative and only mark as focusable if tabindex is set\n return false;\n}\n\n/**\n * Checks if an element is natively focusable.\n * \n * @param element - Element to check\n * @param tagName - Tag name (lowercase)\n * @returns true if natively focusable\n */\nfunction isNativelyFocusable(element: Element, tagName: string): boolean {\n // Links must have href to be focusable\n if (tagName === 'a' || tagName === 'area') {\n return element.hasAttribute('href');\n }\n\n // Check if in the list of natively focusable elements\n if (NATIVELY_FOCUSABLE_ELEMENTS.includes(tagName)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Checks if an element is disabled.\n * \n * @param element - Element to check\n * @returns true if disabled\n */\nfunction isDisabled(element: Element): boolean {\n // Check native disabled attribute\n if ('disabled' in element) {\n const htmlElement = element as HTMLInputElement | HTMLButtonElement | HTMLSelectElement | HTMLTextAreaElement;\n if (htmlElement.disabled) {\n return true;\n }\n }\n\n // Check aria-disabled\n const ariaDisabled = element.getAttribute('aria-disabled');\n if (ariaDisabled === 'true') {\n return true;\n }\n\n return false;\n}\n","/**\n * Accessibility tree builder.\n * \n * Builds the complete accessibility tree from a DOM tree by integrating\n * all extraction components (role, name, description, state, value, focus).\n * \n * Supports transparent traversal through role-less elements, text node\n * capture as staticText nodes, shadow DOM traversal, and CSS hidden state.\n */\n\nimport type { AccessibleNode, AnnouncementModel } from '../model/types.js';\nimport { CURRENT_MODEL_VERSION } from '../model/types.js';\nimport { computeAccessibleName, computeAccessibleDescription } from './aria-name.js';\nimport { computeRole, isAccessible } from './role-mapper.js';\nimport { extractState, extractValue } from './state-extractor.js';\nimport { extractFocusInfo } from './focus-extractor.js';\n\n/**\n * Warning emitted during tree building.\n */\nexport interface TreeBuildWarning {\n message: string;\n element: Element;\n}\n\n/**\n * Result of tree building.\n */\nexport interface TreeBuildResult {\n model: AnnouncementModel;\n warnings: TreeBuildWarning[];\n}\n\n/**\n * Error thrown when selector filtering fails.\n */\nexport class SelectorError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SelectorError';\n }\n}\n\n/**\n * Checks whether an element is hidden from the accessibility tree.\n * \n * Checks aria-hidden=\"true\", display: none, and visibility: hidden.\n * Gracefully skips CSS checks when getComputedStyle is unavailable.\n * \n * @param element - Element to check\n * @returns true if the element is hidden\n */\nfunction isHidden(element: Element): boolean {\n // Check aria-hidden on element itself\n if (element.getAttribute('aria-hidden') === 'true') return true;\n\n // Check CSS hidden state if getComputedStyle is available\n if (typeof getComputedStyle === 'function') {\n try {\n const style = getComputedStyle(element);\n if (style.display === 'none') return true;\n if (style.visibility === 'hidden') return true;\n } catch {\n // Environment doesn't support getComputedStyle — skip CSS checks\n }\n }\n\n return false;\n}\n\n/**\n * Processes a single child node (Text or Element) and appends resulting\n * AccessibleNodes to the children array.\n * \n * For Text nodes: creates a staticText AccessibleNode with trimmed text.\n * For Element nodes: checks hidden/accessible state; if role-less, does\n * transparent traversal via collectChildrenFromRolelessElement.\n * \n * @param node - DOM node to process\n * @param children - Array to append resulting AccessibleNodes to\n * @param warnings - Array to collect warnings\n */\nfunction processChildNode(\n node: Node,\n children: AccessibleNode[],\n warnings: TreeBuildWarning[]\n): void {\n if (node.nodeType === 3) { // TEXT_NODE\n const text = (node.textContent || '').trim();\n if (text.length > 0) {\n children.push({\n role: 'staticText',\n name: text,\n state: {},\n focus: { focusable: false },\n children: [],\n });\n }\n return;\n }\n if (node.nodeType === 1) { // ELEMENT_NODE\n const element = node as Element;\n if (isHidden(element)) return;\n if (!isAccessible(element)) {\n // Transparent traversal: collect children from role-less element\n const grandchildren = collectChildrenFromRolelessElement(element, warnings);\n children.push(...grandchildren);\n return;\n }\n const childNode = buildNodeRecursive(element, warnings);\n if (childNode) children.push(childNode);\n }\n}\n\n/**\n * Collects accessible children from a role-less element (transparent traversal).\n * \n * Traverses shadow DOM first (if present), then light DOM childNodes.\n * Returns a flat array of AccessibleNodes to be merged into the parent's children.\n * \n * @param element - Role-less element to collect children from\n * @param warnings - Array to collect warnings\n * @returns Flat array of AccessibleNodes\n */\nfunction collectChildrenFromRolelessElement(\n element: Element,\n warnings: TreeBuildWarning[]\n): AccessibleNode[] {\n const children: AccessibleNode[] = [];\n // Traverse shadow DOM first if present\n if (element.shadowRoot) {\n for (const child of Array.from(element.shadowRoot.childNodes)) {\n processChildNode(child, children, warnings);\n }\n }\n // Then light DOM\n for (const child of Array.from(element.childNodes)) {\n processChildNode(child, children, warnings);\n }\n return children;\n}\n\n/**\n * Builds an accessibility tree from a DOM element.\n * \n * Traverses the DOM tree depth-first, applies all extractors,\n * filters inaccessible elements, and builds the hierarchical tree.\n * \n * @param rootElement - Root DOM element to build tree from\n * @param sourceHash - Optional hash of source HTML for change detection\n * @returns Announcement model and warnings\n */\nexport function buildAccessibilityTree(\n rootElement: Element,\n sourceHash?: string\n): TreeBuildResult {\n const warnings: TreeBuildWarning[] = [];\n \n // If root element is hidden, return empty generic container\n if (isHidden(rootElement)) {\n const model: AnnouncementModel = {\n version: CURRENT_MODEL_VERSION,\n root: {\n role: 'generic',\n name: '',\n state: {},\n focus: { focusable: false },\n children: [],\n },\n metadata: {\n extractedAt: new Date().toISOString(),\n ...(sourceHash && { sourceHash }),\n },\n };\n return { model, warnings };\n }\n\n // Build the root node\n const rootNode = buildNodeRecursive(rootElement, warnings);\n \n // If root element is not accessible, create a generic container\n const accessibleRoot = rootNode || createGenericContainer(rootElement, warnings);\n \n // Create the announcement model\n const model: AnnouncementModel = {\n version: CURRENT_MODEL_VERSION,\n root: accessibleRoot,\n metadata: {\n extractedAt: new Date().toISOString(),\n ...(sourceHash && { sourceHash }),\n },\n };\n \n return { model, warnings };\n}\n\n/**\n * Builds accessibility trees for elements matching a CSS selector.\n * \n * Uses querySelector/querySelectorAll to find matching elements,\n * then builds an accessibility tree for each match.\n * \n * @param rootElement - Root DOM element to search within\n * @param selector - CSS selector to match elements\n * @param sourceHash - Optional hash of source HTML for change detection\n * @returns Array of announcement models and warnings\n * @throws SelectorError if no elements match the selector\n */\nexport function buildAccessibilityTreeWithSelector(\n rootElement: Element,\n selector: string,\n sourceHash?: string\n): TreeBuildResult[] {\n const document = rootElement.ownerDocument;\n if (!document) {\n throw new SelectorError('Element has no owner document');\n }\n \n // Find all matching elements\n let matchingElements: Element[];\n try {\n // Check if rootElement itself matches\n if (rootElement.matches(selector)) {\n matchingElements = [rootElement];\n } else {\n // Query for matching descendants\n matchingElements = Array.from(rootElement.querySelectorAll(selector));\n }\n } catch (error) {\n throw new SelectorError(`Invalid CSS selector: \"${selector}\". ${error instanceof Error ? error.message : String(error)}`);\n }\n \n // Error if no matches found\n if (matchingElements.length === 0) {\n throw new SelectorError(`No elements match selector: \"${selector}\"`);\n }\n \n // Build accessibility tree for each matching element\n const results: TreeBuildResult[] = [];\n for (const element of matchingElements) {\n const result = buildAccessibilityTree(element, sourceHash);\n results.push(result);\n }\n \n return results;\n}\n\n/**\n * Recursively builds an accessible node from a DOM element.\n * \n * Checks hidden state first, then accessibility. If the element has no role,\n * transparent traversal is not done here (it's handled by processChildNode\n * in the parent's iteration). This function is only called for elements\n * that are known to be accessible.\n * \n * @param element - DOM element to build node from\n * @param warnings - Array to collect warnings\n * @returns Accessible node or null if element is hidden or not accessible\n */\nfunction buildNodeRecursive(\n element: Element,\n warnings: TreeBuildWarning[]\n): AccessibleNode | null {\n // Check hidden state first (before any extraction)\n if (isHidden(element)) {\n return null;\n }\n\n // Check if element should be included in accessibility tree\n if (!isAccessible(element)) {\n return null;\n }\n \n // Extract role\n const roleResult = computeRole(element);\n warnings.push(...roleResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // If no role, element is not accessible\n if (!roleResult.role) {\n return null;\n }\n \n // Extract accessible name\n const nameResult = computeAccessibleName(element);\n warnings.push(...nameResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // Extract accessible description\n const descResult = computeAccessibleDescription(element);\n warnings.push(...descResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // Extract state\n const stateResult = extractState(element);\n warnings.push(...stateResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // Extract value\n const valueResult = extractValue(element);\n warnings.push(...valueResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // Extract focus info\n const focusInfo = extractFocusInfo(element);\n \n // Build children from childNodes (includes Text nodes)\n const children: AccessibleNode[] = [];\n // Shadow DOM first\n if (element.shadowRoot) {\n for (const child of Array.from(element.shadowRoot.childNodes)) {\n processChildNode(child, children, warnings);\n }\n }\n // Light DOM\n for (const child of Array.from(element.childNodes)) {\n processChildNode(child, children, warnings);\n }\n \n // Create the accessible node\n const node: AccessibleNode = {\n role: roleResult.role,\n name: nameResult.name,\n ...(descResult.description && { description: descResult.description }),\n ...(valueResult.value && { value: valueResult.value }),\n state: stateResult.state,\n focus: focusInfo,\n children,\n };\n \n return node;\n}\n\n/**\n * Creates a generic container node when root element is not accessible.\n * \n * This ensures we always have a valid root node even if the root element\n * itself is not accessible (e.g., a plain div).\n * Uses childNodes and processChildNode for text node and transparent traversal support.\n * \n * @param rootElement - Root DOM element\n * @param warnings - Array to collect warnings\n * @returns Generic container node with accessible children\n */\nfunction createGenericContainer(\n rootElement: Element,\n warnings: TreeBuildWarning[]\n): AccessibleNode {\n // Build children from root element using childNodes\n const children: AccessibleNode[] = [];\n // Shadow DOM first\n if (rootElement.shadowRoot) {\n for (const child of Array.from(rootElement.shadowRoot.childNodes)) {\n processChildNode(child, children, warnings);\n }\n }\n // Light DOM\n for (const child of Array.from(rootElement.childNodes)) {\n processChildNode(child, children, warnings);\n }\n \n // Create a generic container\n return {\n role: 'generic',\n name: '',\n state: {},\n focus: {\n focusable: false,\n },\n children,\n };\n}\n","/**\n * Runtime Accessibility Timeline - Public API\n *\n * Exports all public types, interfaces, and factory functions for the\n * Runtime Accessibility Engine. This module provides:\n *\n * - Event type system (EventType, AccessibilityEvent, payloads)\n * - Runtime engine (createEngine)\n * - Timeline generation (createTimelineGenerator)\n * - Interaction execution (executeAction, executeSequence)\n * - Built-in patterns (getBuiltinPattern)\n * - Heuristic analysis (createHeuristicAnalyzer)\n * - Serialization (serializeTimeline, deserializeTimeline, etc.)\n * - Stable CSS selector generation (generateSelector)\n */\n\n// Types and interfaces\nexport * from './types.js';\n\n// Engine\nexport { createEngine } from './engine.js';\nexport type { EngineOptions, RuntimeAccessibilityEngine } from './engine.js';\n\n// Timeline Generator\nexport { createTimelineGenerator } from './timeline-generator.js';\nexport type { TimelineGeneratorOptions, TimelineGenerator } from './timeline-generator.js';\n\n// Interaction execution\nexport { executeAction, executeSequence } from './interactions.js';\n\n// Built-in interaction patterns\nexport { getBuiltinPattern } from './patterns.js';\nexport type { PatternSelectorMap, BuiltinPatternName } from './patterns.js';\n\n// Heuristic warning analyzer\nexport { createHeuristicAnalyzer } from './heuristics.js';\nexport type { HeuristicConfig, HeuristicAnalyzer } from './heuristics.js';\n\n// Serialization\nexport {\n serializeTimeline,\n deserializeTimeline,\n serializeEvent,\n deserializeEvent,\n serializeInteractionSequence,\n deserializeInteractionSequence,\n timelinesEqual,\n} from './serialization.js';\n\n// Stable CSS selector generation\nexport { generateSelector } from './selector.js';\n\n// Behavior Diff Engine\nexport { diffTimelines } from './diff-engine.js';\nexport type { BehaviorDiffReport, DiffEntry } from './diff-engine.js';\n\n// Severity Classification\nexport { classifyDiff } from './severity.js';\nexport type { SeverityLevel, ClassifiedDiffEntry, ClassifiedDiffReport } from './severity.js';\n\n// Baseline Storage\nexport { createBaselineStorage } from './baseline-storage.js';\nexport type { BaselineFile, BaselineStorage } from './baseline-storage.js';\n\n// Verbosity Analyzer\nexport { analyzeVerbosity, formatVerbosityReport } from './verbosity-analyzer.js';\nexport type {\n VerbositySeverity,\n VerbosityPattern,\n VerbosityFinding,\n VerbosityReport,\n VerbosityConfig,\n} from './verbosity-analyzer.js';\n","/**\n * Stable CSS Selector Generation\n *\n * Generates unique, deterministic CSS selectors for DOM elements.\n * The selector strategy prioritizes stability and readability:\n *\n * 1. If the element has an ID, return `#id`\n * 2. Walk up from the element to the document root, building a path\n * 3. At each level, try tag name alone, then tag+classes, then tag:nth-child(n)\n * 4. Stop building the path when the partial selector already uniquely identifies the element\n */\n\n/**\n * Generate a stable CSS selector that uniquely identifies the given element\n * within its document.\n *\n * The selector is deterministic: given the same DOM structure, the same element\n * will always produce the same selector string.\n */\nexport function generateSelector(element: Element): string {\n // If the element has an ID, use it directly (IDs are unique within a document)\n if (element.id) {\n return `#${escapeCSSIdentifier(element.id)}`;\n }\n\n const document = element.ownerDocument;\n if (!document) {\n return getTagName(element);\n }\n\n // Build path segments from element up to document root\n const segments: string[] = [];\n let current: Element | null = element;\n\n while (current && current !== document.documentElement) {\n const segment = buildSegment(current, document);\n segments.unshift(segment);\n\n // Check if the current partial path already uniquely identifies the element\n const partialSelector = segments.join(' > ');\n try {\n const matches = document.querySelectorAll(partialSelector);\n if (matches.length === 1 && matches[0] === element) {\n return partialSelector;\n }\n } catch {\n // If querySelectorAll fails (invalid selector), continue building path\n }\n\n current = current.parentElement;\n }\n\n // Include html root if needed\n if (segments.length === 0) {\n return getTagName(element);\n }\n\n const fullSelector = segments.join(' > ');\n\n // Final uniqueness check - if still not unique, shouldn't happen for well-formed DOM\n // but return what we have as it's the most specific path we can build\n return fullSelector;\n}\n\n/**\n * Build a selector segment for a single element in the path.\n * Tries strategies in order of preference: tag alone, tag+classes, tag:nth-child.\n */\nfunction buildSegment(element: Element, _document: Document): string {\n const tag = getTagName(element);\n const parent = element.parentElement;\n\n // Strategy 1: Tag name alone is unique among siblings\n if (parent) {\n const siblingsWithSameTag = Array.from(parent.children).filter(\n (child) => getTagName(child) === tag\n );\n if (siblingsWithSameTag.length === 1) {\n return tag;\n }\n } else {\n // No parent - tag alone is our best option at root level\n return tag;\n }\n\n // Strategy 2: Tag + class combination is unique among siblings\n const classes = getStableClasses(element);\n if (classes.length > 0) {\n const tagWithClasses = `${tag}.${classes.join('.')}`;\n if (parent) {\n const siblingsMatchingClasses = Array.from(parent.children).filter(\n (child) => {\n if (getTagName(child) !== tag) return false;\n return classes.every((cls) => child.classList.contains(cls));\n }\n );\n if (siblingsMatchingClasses.length === 1) {\n return tagWithClasses;\n }\n }\n }\n\n // Strategy 3: nth-child fallback (always unique among siblings)\n const index = getNthChildIndex(element);\n return `${tag}:nth-child(${index})`;\n}\n\n/**\n * Get the lowercase tag name for an element.\n */\nfunction getTagName(element: Element): string {\n return element.tagName.toLowerCase();\n}\n\n/**\n * Get sorted, stable class names for an element.\n * Filters out classes that look dynamic (contain random characters/hashes).\n * Sorting ensures deterministic output regardless of class order in markup.\n */\nfunction getStableClasses(element: Element): string[] {\n const classes = Array.from(element.classList);\n if (classes.length === 0) return [];\n\n // Filter out classes that look like generated hashes (e.g., CSS modules)\n const stableClasses = classes.filter((cls) => !looksLikeDynamicClass(cls));\n\n // Sort for determinism\n return stableClasses.sort().map(escapeCSSIdentifier);\n}\n\n/**\n * Heuristic to detect dynamic/generated class names.\n * Classes with patterns like hex hashes, random strings, or auto-generated\n * suffixes are considered unstable.\n */\nfunction looksLikeDynamicClass(className: string): boolean {\n // Classes that are purely hex strings of 5+ chars\n if (/^[a-f0-9]{5,}$/i.test(className)) return true;\n\n // Classes ending with a hash-like suffix (e.g., \"button_a1b2c3\")\n if (/[_-][a-f0-9]{5,}$/i.test(className)) return true;\n\n // CSS module style hashes (e.g., \"styles__button___2xF3d\")\n if (/_{2,}[A-Za-z0-9]{4,}$/.test(className)) return true;\n\n return false;\n}\n\n/**\n * Get the 1-based nth-child index of an element among its parent's children.\n */\nfunction getNthChildIndex(element: Element): number {\n const parent = element.parentElement;\n if (!parent) return 1;\n\n const children = Array.from(parent.children);\n const index = children.indexOf(element);\n return index + 1;\n}\n\n/**\n * Escape special characters in a CSS identifier.\n * Handles characters that have special meaning in CSS selectors.\n */\nfunction escapeCSSIdentifier(value: string): string {\n // If the value is empty, return it as-is\n if (!value) return value;\n\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n const code = char.charCodeAt(0);\n\n // If it starts with a digit, escape it\n if (i === 0 && code >= 0x30 && code <= 0x39) {\n result += `\\\\3${char} `;\n continue;\n }\n\n // Characters that need escaping in CSS identifiers\n if (\n char === '!' ||\n char === '\"' ||\n char === '#' ||\n char === '$' ||\n char === '%' ||\n char === '&' ||\n char === \"'\" ||\n char === '(' ||\n char === ')' ||\n char === '*' ||\n char === '+' ||\n char === ',' ||\n char === '.' ||\n char === '/' ||\n char === ':' ||\n char === ';' ||\n char === '<' ||\n char === '=' ||\n char === '>' ||\n char === '?' ||\n char === '@' ||\n char === '[' ||\n char === '\\\\' ||\n char === ']' ||\n char === '^' ||\n char === '`' ||\n char === '{' ||\n char === '|' ||\n char === '}' ||\n char === '~' ||\n char === ' '\n ) {\n result += `\\\\${char}`;\n continue;\n }\n\n result += char;\n }\n\n return result;\n}\n","/**\n * Focus Observer\n *\n * Observes focus changes on a document and emits FOCUS_CHANGED accessibility\n * events. Tracks the previously focused element to populate the previousTarget\n * field in each event.\n *\n * @module runtime/observers/focus-observer\n */\n\nimport type { AccessibilityEvent, EventTarget as A11yEventTarget } from '../types';\nimport { generateSelector } from '../selector';\n\n// ---------------------------------------------------------------------------\n// Accessible Name Computation (self-contained)\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the accessible name for an element.\n * Checks aria-label, then aria-labelledby (resolves referenced element textContent),\n * then falls back to the element's own textContent.\n */\nfunction computeAccessibleName(element: Element, document: Document): string {\n // 1. aria-label takes precedence\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n // 2. aria-labelledby: resolve referenced element(s) text content\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy && labelledBy.trim()) {\n const ids = labelledBy.trim().split(/\\s+/);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = document.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n const combined = parts.join(' ');\n if (combined) {\n return combined;\n }\n }\n\n // 3. Fall back to element's own textContent\n const textContent = element.textContent;\n if (textContent && textContent.trim()) {\n return textContent.trim();\n }\n\n return '';\n}\n\n// ---------------------------------------------------------------------------\n// Implicit Role Mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Determine the ARIA role of an element.\n * Checks the explicit `role` attribute first, then falls back to implicit\n * role mapping based on tag name and attributes.\n */\nfunction getElementRole(element: Element): string {\n // Explicit role takes priority\n const explicitRole = element.getAttribute('role');\n if (explicitRole && explicitRole.trim()) {\n return explicitRole.trim();\n }\n\n // Implicit role mapping\n const tagName = element.tagName.toLowerCase();\n\n switch (tagName) {\n case 'button':\n return 'button';\n case 'a':\n return element.hasAttribute('href') ? 'link' : 'generic';\n case 'input': {\n const type = (element.getAttribute('type') || 'text').toLowerCase();\n switch (type) {\n case 'button':\n case 'submit':\n case 'reset':\n case 'image':\n return 'button';\n case 'checkbox':\n return 'checkbox';\n case 'radio':\n return 'radio';\n case 'range':\n return 'slider';\n case 'search':\n return 'searchbox';\n default:\n return 'textbox';\n }\n }\n case 'textarea':\n return 'textbox';\n case 'select':\n return element.hasAttribute('multiple') ? 'listbox' : 'combobox';\n case 'nav':\n return 'navigation';\n case 'main':\n return 'main';\n case 'header':\n return 'banner';\n case 'footer':\n return 'contentinfo';\n case 'aside':\n return 'complementary';\n case 'form':\n return 'form';\n case 'section':\n return element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby')\n ? 'region'\n : 'generic';\n case 'article':\n return 'article';\n case 'dialog':\n return 'dialog';\n case 'table':\n return 'table';\n case 'ul':\n case 'ol':\n return 'list';\n case 'li':\n return 'listitem';\n case 'img':\n return element.getAttribute('alt') === '' ? 'presentation' : 'img';\n case 'h1':\n case 'h2':\n case 'h3':\n case 'h4':\n case 'h5':\n case 'h6':\n return 'heading';\n case 'option':\n return 'option';\n case 'progress':\n return 'progressbar';\n case 'output':\n return 'status';\n case 'menu':\n return 'menu';\n default:\n return 'generic';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Focus Observer\n// ---------------------------------------------------------------------------\n\n/** Callback type for emitting accessibility events from the observer. */\nexport type FocusEventEmitter = (event: AccessibilityEvent) => void;\n\nexport interface FocusObserverOptions {\n /** The document to observe focus changes on */\n document: Document;\n /** Callback to emit accessibility events */\n onEvent: FocusEventEmitter;\n /** Function to get the current timestamp (ms since session start) */\n getTimestamp: () => number;\n}\n\nexport interface FocusObserver {\n /** Start listening for focus changes */\n start(): void;\n /** Stop listening for focus changes */\n stop(): void;\n /** Whether the observer is currently active */\n readonly isActive: boolean;\n}\n\n/**\n * Creates a FocusObserver that listens to focusin events on the document\n * and emits FOCUS_CHANGED accessibility events.\n */\nexport function createFocusObserver(options: FocusObserverOptions): FocusObserver {\n const { document: doc, onEvent, getTimestamp } = options;\n\n let active = false;\n let previousTarget: A11yEventTarget | null = null;\n\n function buildEventTarget(element: Element): A11yEventTarget {\n return {\n role: getElementRole(element),\n accessibleName: computeAccessibleName(element, doc),\n selector: generateSelector(element),\n };\n }\n\n function handleFocusIn(event: Event): void {\n if (!active) return;\n\n const target = event.target;\n if (!target || !(target instanceof doc.defaultView!.Element)) {\n return;\n }\n\n const currentTarget = buildEventTarget(target);\n\n const a11yEvent: AccessibilityEvent = {\n type: 'FOCUS_CHANGED',\n timestamp: getTimestamp(),\n target: currentTarget,\n payload: {\n kind: 'focus_changed',\n previousTarget: previousTarget,\n },\n };\n\n onEvent(a11yEvent);\n previousTarget = currentTarget;\n }\n\n return {\n start(): void {\n if (active) return;\n active = true;\n previousTarget = null;\n doc.addEventListener('focusin', handleFocusIn);\n },\n\n stop(): void {\n if (!active) return;\n active = false;\n doc.removeEventListener('focusin', handleFocusIn);\n },\n\n get isActive(): boolean {\n return active;\n },\n };\n}\n","/**\n * Mutation Observer for Accessibility-Relevant Attribute Changes\n *\n * Wraps MutationObserver to detect changes to:\n * - `role` attribute → emits ROLE_CHANGED events\n * - `aria-label`, `aria-labelledby` → emits ACCESSIBLE_NAME_CHANGED events\n * - `aria-expanded`, `aria-selected`, `aria-checked`, `aria-disabled`, `aria-hidden` → emits STATE_CHANGED events\n *\n * Filters out irrelevant mutations (text content in non-live regions, style changes).\n * Uses `attributeOldValue: true` to capture previous values for diff reporting.\n *\n * @module runtime/observers/mutation-observer\n */\n\nimport type {\n AccessibilityEvent,\n EventTarget as A11yEventTarget,\n RoleChangedPayload,\n AccessibleNameChangedPayload,\n StateChangedPayload,\n} from '../types';\nimport { generateSelector } from '../selector';\n\n// ---------------------------------------------------------------------------\n// Observed attribute sets\n// ---------------------------------------------------------------------------\n\n/** Attribute that triggers ROLE_CHANGED */\nconst ROLE_ATTRIBUTE = 'role';\n\n/** Attributes that trigger ACCESSIBLE_NAME_CHANGED */\nconst NAME_ATTRIBUTES = new Set(['aria-label', 'aria-labelledby']);\n\n/** Attributes that trigger STATE_CHANGED */\nconst STATE_ATTRIBUTES = new Set([\n 'aria-expanded',\n 'aria-selected',\n 'aria-checked',\n 'aria-disabled',\n 'aria-hidden',\n]);\n\n/** All observed attributes combined (for MutationObserver attributeFilter) */\nconst OBSERVED_ATTRIBUTES = [\n ROLE_ATTRIBUTE,\n 'aria-label',\n 'aria-labelledby',\n 'aria-expanded',\n 'aria-selected',\n 'aria-checked',\n 'aria-disabled',\n 'aria-hidden',\n];\n\n// ---------------------------------------------------------------------------\n// Accessible Name Computation (self-contained)\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the accessible name for an element.\n * Checks aria-label, then aria-labelledby (resolves referenced element textContent),\n * then falls back to the element's own textContent.\n */\nfunction computeAccessibleName(element: Element, document: Document): string {\n // 1. aria-label takes precedence\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n // 2. aria-labelledby: resolve referenced element(s) text content\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy && labelledBy.trim()) {\n const ids = labelledBy.trim().split(/\\s+/);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = document.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n const combined = parts.join(' ');\n if (combined) {\n return combined;\n }\n }\n\n // 3. Fall back to element's own textContent\n const textContent = element.textContent;\n if (textContent && textContent.trim()) {\n return textContent.trim();\n }\n\n return '';\n}\n\n// ---------------------------------------------------------------------------\n// Implicit Role Mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Determine the ARIA role of an element.\n * Checks the explicit `role` attribute first, then falls back to implicit\n * role mapping based on tag name and attributes.\n */\nfunction getElementRole(element: Element): string {\n // Explicit role takes priority\n const explicitRole = element.getAttribute('role');\n if (explicitRole && explicitRole.trim()) {\n return explicitRole.trim();\n }\n\n // Implicit role mapping\n const tagName = element.tagName.toLowerCase();\n\n switch (tagName) {\n case 'button':\n return 'button';\n case 'a':\n return element.hasAttribute('href') ? 'link' : 'generic';\n case 'input': {\n const type = (element.getAttribute('type') || 'text').toLowerCase();\n switch (type) {\n case 'button':\n case 'submit':\n case 'reset':\n case 'image':\n return 'button';\n case 'checkbox':\n return 'checkbox';\n case 'radio':\n return 'radio';\n case 'range':\n return 'slider';\n case 'search':\n return 'searchbox';\n default:\n return 'textbox';\n }\n }\n case 'textarea':\n return 'textbox';\n case 'select':\n return element.hasAttribute('multiple') ? 'listbox' : 'combobox';\n case 'nav':\n return 'navigation';\n case 'main':\n return 'main';\n case 'header':\n return 'banner';\n case 'footer':\n return 'contentinfo';\n case 'aside':\n return 'complementary';\n case 'form':\n return 'form';\n case 'section':\n return element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby')\n ? 'region'\n : 'generic';\n case 'article':\n return 'article';\n case 'dialog':\n return 'dialog';\n case 'table':\n return 'table';\n case 'ul':\n case 'ol':\n return 'list';\n case 'li':\n return 'listitem';\n case 'img':\n return element.getAttribute('alt') === '' ? 'presentation' : 'img';\n case 'h1':\n case 'h2':\n case 'h3':\n case 'h4':\n case 'h5':\n case 'h6':\n return 'heading';\n case 'option':\n return 'option';\n case 'progress':\n return 'progressbar';\n case 'output':\n return 'status';\n case 'menu':\n return 'menu';\n default:\n return 'generic';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Mutation Observer Types\n// ---------------------------------------------------------------------------\n\n/** Callback type for emitting accessibility events from the observer. */\nexport type MutationEventEmitter = (event: AccessibilityEvent) => void;\n\nexport interface MutationObserverOptions {\n /** The document to observe attribute changes on */\n document: Document;\n /** Callback to emit accessibility events */\n onEvent: MutationEventEmitter;\n /** Function to get the current timestamp (ms since session start) */\n getTimestamp: () => number;\n}\n\nexport interface AccessibilityMutationObserver {\n /** Start observing the document for attribute mutations */\n start(): void;\n /** Stop observing and disconnect the MutationObserver */\n stop(): void;\n /** Whether the observer is currently active */\n readonly isActive: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Mutation Observer Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an accessibility-focused MutationObserver that watches for\n * role, accessible name, and ARIA state attribute changes, emitting\n * normalized accessibility events.\n *\n * Only observes attribute mutations on the specific ARIA attributes listed.\n * Text content changes, style changes, and child list mutations are ignored.\n */\nexport function createMutationObserver(\n options: MutationObserverOptions\n): AccessibilityMutationObserver {\n const { document: doc, onEvent, getTimestamp } = options;\n\n let observer: MutationObserver | null = null;\n let active = false;\n\n function handleMutations(mutations: MutationRecord[]): void {\n if (!active) return;\n\n for (const mutation of mutations) {\n if (mutation.type !== 'attributes') {\n continue;\n }\n\n const attributeName = mutation.attributeName;\n if (!attributeName) {\n continue;\n }\n\n const target = mutation.target;\n if (!(target instanceof Element)) {\n continue;\n }\n\n // Route to the appropriate handler based on attribute category\n if (attributeName === ROLE_ATTRIBUTE) {\n handleRoleChange(target, mutation.oldValue);\n } else if (NAME_ATTRIBUTES.has(attributeName)) {\n handleNameChange(target, attributeName, mutation.oldValue);\n } else if (STATE_ATTRIBUTES.has(attributeName)) {\n handleStateChange(target, attributeName, mutation.oldValue);\n }\n // All other attributes are filtered out by the attributeFilter config\n }\n }\n\n function handleRoleChange(element: Element, oldValue: string | null): void {\n const previousRole = oldValue?.trim() || getImplicitRole(element);\n const newRole = element.getAttribute('role')?.trim() || getImplicitRole(element);\n\n // Don't emit if the effective role hasn't actually changed\n if (previousRole === newRole) {\n return;\n }\n\n const eventTarget = buildEventTarget(element);\n const payload: RoleChangedPayload = {\n kind: 'role_changed',\n previousRole,\n newRole,\n };\n\n onEvent({\n type: 'ROLE_CHANGED',\n timestamp: getTimestamp(),\n target: eventTarget,\n payload,\n });\n }\n\n function handleNameChange(\n element: Element,\n attributeName: string,\n oldValue: string | null\n ): void {\n let previousName: string;\n let newName: string;\n\n if (attributeName === 'aria-label') {\n // For aria-label changes, the old value is the previous label\n previousName = oldValue?.trim() || '';\n newName = computeAccessibleName(element, doc);\n\n // If old value was empty, try to compute what the name was from other sources\n if (!previousName && oldValue === null) {\n // aria-label was just added; previous name was from labelledby or textContent\n // We can approximate by checking other sources\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy) {\n previousName = resolveAriaLabelledBy(element, labelledBy);\n } else {\n previousName = element.textContent?.trim() || '';\n }\n }\n } else {\n // aria-labelledby changed\n // Resolve the old labelledby references for the previous name\n previousName = oldValue ? resolveAriaLabelledBy(element, oldValue) : '';\n if (!previousName && oldValue === null) {\n // aria-labelledby was just added; previous name was from aria-label or textContent\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel) {\n previousName = ariaLabel.trim();\n } else {\n previousName = element.textContent?.trim() || '';\n }\n }\n newName = computeAccessibleName(element, doc);\n }\n\n // Don't emit if the accessible name hasn't actually changed\n if (previousName === newName) {\n return;\n }\n\n const eventTarget = buildEventTarget(element);\n const payload: AccessibleNameChangedPayload = {\n kind: 'accessible_name_changed',\n previousName,\n newName,\n };\n\n onEvent({\n type: 'ACCESSIBLE_NAME_CHANGED',\n timestamp: getTimestamp(),\n target: eventTarget,\n payload,\n });\n }\n\n function handleStateChange(\n element: Element,\n attributeName: string,\n oldValue: string | null\n ): void {\n const currentValue = element.getAttribute(attributeName);\n\n // Normalize values: treat \"true\"/\"false\" as booleans\n const normalizedOld = normalizeStateValue(oldValue);\n const normalizedNew = normalizeStateValue(currentValue);\n\n // Don't emit if the state hasn't actually changed\n if (normalizedOld === normalizedNew) {\n return;\n }\n\n const eventTarget = buildEventTarget(element);\n const payload: StateChangedPayload = {\n kind: 'state_changed',\n attribute: attributeName,\n previousValue: normalizedOld,\n newValue: normalizedNew,\n };\n\n onEvent({\n type: 'STATE_CHANGED',\n timestamp: getTimestamp(),\n target: eventTarget,\n payload,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n function buildEventTarget(element: Element): A11yEventTarget {\n return {\n role: getElementRole(element),\n accessibleName: computeAccessibleName(element, doc),\n selector: generateSelector(element),\n };\n }\n\n /**\n * Get the implicit role for an element based on tag name.\n * Used as fallback when the explicit role attribute is absent.\n */\n function getImplicitRole(element: Element): string {\n const tagName = element.tagName.toLowerCase();\n switch (tagName) {\n case 'button':\n return 'button';\n case 'a':\n return element.hasAttribute('href') ? 'link' : 'generic';\n case 'input': {\n const type = (element.getAttribute('type') || 'text').toLowerCase();\n switch (type) {\n case 'button':\n case 'submit':\n case 'reset':\n case 'image':\n return 'button';\n case 'checkbox':\n return 'checkbox';\n case 'radio':\n return 'radio';\n default:\n return 'textbox';\n }\n }\n default:\n return 'generic';\n }\n }\n\n function resolveAriaLabelledBy(\n element: Element,\n idRefs: string\n ): string {\n const ownerDoc = element.ownerDocument;\n if (!ownerDoc) {\n return '';\n }\n\n const ids = idRefs.trim().split(/\\s+/).filter(Boolean);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = ownerDoc.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n\n return parts.join(' ');\n }\n\n function normalizeStateValue(value: string | null): string | boolean | null {\n if (value === null) {\n return null;\n }\n if (value === 'true') {\n return true;\n }\n if (value === 'false') {\n return false;\n }\n return value;\n }\n\n // ---------------------------------------------------------------------------\n // Public interface\n // ---------------------------------------------------------------------------\n\n return {\n start(): void {\n if (active) return;\n active = true;\n\n observer = new MutationObserver(handleMutations);\n observer.observe(doc.body ?? doc.documentElement, {\n attributes: true,\n attributeOldValue: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n subtree: true,\n });\n },\n\n stop(): void {\n if (!active) return;\n active = false;\n\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n },\n\n get isActive(): boolean {\n return active;\n },\n };\n}\n","/**\n * Live Region Observer\n *\n * Detects text content changes within elements marked with aria-live or\n * implicit live region roles (alert, status, log, marquee, timer).\n * Emits ANNOUNCEMENT events with politeness level and announced text.\n *\n * Handles:\n * - Elements with explicit aria-live attribute (polite/assertive)\n * - Elements with role=\"alert\" (implicit assertive)\n * - Elements with role=\"status\"/\"log\"/\"marquee\"/\"timer\" (implicit polite)\n * - aria-atomic=\"true\" (read entire region vs changed nodes only)\n * - Dynamically added live regions (watched via document-level observer)\n */\n\nimport type { AccessibilityEvent, EventTarget as A11yEventTarget } from '../types';\nimport { generateSelector } from '../selector';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Callback invoked when the observer detects a live region announcement. */\nexport type LiveRegionEventCallback = (event: Omit<AccessibilityEvent, 'timestamp'>) => void;\n\n/** Roles that implicitly create live regions. */\nconst IMPLICIT_LIVE_ROLES = new Set(['alert', 'status', 'log', 'marquee', 'timer']);\n\n/** Map from implicit role to politeness level. */\nconst ROLE_POLITENESS_MAP: Record<string, 'polite' | 'assertive'> = {\n alert: 'assertive',\n status: 'polite',\n log: 'polite',\n marquee: 'polite',\n timer: 'polite',\n};\n\n// ---------------------------------------------------------------------------\n// Observer Interface\n// ---------------------------------------------------------------------------\n\nexport interface LiveRegionObserver {\n /** Start observing live regions for content changes. */\n start(): void;\n /** Stop observing and clean up all mutation observers. */\n stop(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a live region observer that watches for content changes in\n * aria-live regions and emits ANNOUNCEMENT events.\n *\n * @param document - The document to observe\n * @param callback - Function called with AccessibilityEvent for each announcement\n * @returns LiveRegionObserver with start/stop lifecycle methods\n */\nexport function createLiveRegionObserver(\n document: Document,\n callback: LiveRegionEventCallback\n): LiveRegionObserver {\n /** MutationObserver for content changes within known live regions. */\n let contentObserver: MutationObserver | null = null;\n\n /** MutationObserver for detecting new live regions added to the document. */\n let documentObserver: MutationObserver | null = null;\n\n /** Set of currently tracked live region elements. */\n const trackedRegions = new Set<Element>();\n\n // -------------------------------------------------------------------------\n // Helpers\n // -------------------------------------------------------------------------\n\n /**\n * Determine if an element is a live region and return its politeness level.\n * Returns null if the element is not a live region.\n */\n function getLiveRegionPoliteness(element: Element): 'polite' | 'assertive' | null {\n // Explicit aria-live takes precedence\n const ariaLive = element.getAttribute('aria-live');\n if (ariaLive === 'assertive') return 'assertive';\n if (ariaLive === 'polite') return 'polite';\n // aria-live=\"off\" means not a live region\n if (ariaLive === 'off') return null;\n\n // Check implicit live region roles\n const role = element.getAttribute('role');\n if (role && IMPLICIT_LIVE_ROLES.has(role)) {\n return ROLE_POLITENESS_MAP[role] || 'polite';\n }\n\n // If aria-live has another value (non-standard), treat as polite\n if (ariaLive && ariaLive !== 'off') return 'polite';\n\n return null;\n }\n\n /**\n * Determine whether the live region uses atomic reading\n * (entire region text vs only changed nodes).\n */\n function isAtomic(element: Element): boolean {\n return element.getAttribute('aria-atomic') === 'true';\n }\n\n /**\n * Build the EventTarget info for a live region element.\n */\n function buildEventTarget(element: Element): A11yEventTarget {\n const role = element.getAttribute('role') || 'region';\n const accessibleName =\n element.getAttribute('aria-label') ||\n element.getAttribute('aria-labelledby') ||\n '';\n const selector = generateSelector(element);\n\n return { role, accessibleName, selector };\n }\n\n /**\n * Extract text content from a list of added nodes (text nodes and elements).\n */\n function getTextFromNodes(nodes: NodeList): string {\n const parts: string[] = [];\n nodes.forEach((node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent?.trim();\n if (text) parts.push(text);\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n const text = (node as Element).textContent?.trim();\n if (text) parts.push(text);\n }\n });\n return parts.join(' ').trim();\n }\n\n /**\n * Emit an ANNOUNCEMENT event for a live region content change.\n */\n function emitAnnouncement(\n liveRegion: Element,\n text: string,\n politeness: 'polite' | 'assertive'\n ): void {\n if (!text) return;\n\n const target = buildEventTarget(liveRegion);\n\n callback({\n type: 'ANNOUNCEMENT',\n target,\n payload: {\n kind: 'announcement',\n politeness,\n text,\n },\n });\n }\n\n /**\n * Find the closest ancestor (or self) that is a tracked live region.\n */\n function findLiveRegionAncestor(node: Node): Element | null {\n let current: Node | null = node;\n while (current) {\n if (current.nodeType === Node.ELEMENT_NODE && trackedRegions.has(current as Element)) {\n return current as Element;\n }\n current = current.parentNode;\n }\n return null;\n }\n\n // -------------------------------------------------------------------------\n // Content Mutation Handling\n // -------------------------------------------------------------------------\n\n /**\n * Handle mutations within tracked live regions.\n */\n function handleContentMutations(mutations: MutationRecord[]): void {\n // Group mutations by their live region ancestor to avoid duplicate announcements\n const regionChanges = new Map<Element, { addedText: string[]; charDataChanged: boolean }>();\n\n for (const mutation of mutations) {\n const liveRegion = findLiveRegionAncestor(mutation.target);\n if (!liveRegion) continue;\n\n if (!regionChanges.has(liveRegion)) {\n regionChanges.set(liveRegion, { addedText: [], charDataChanged: false });\n }\n const changes = regionChanges.get(liveRegion)!;\n\n if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {\n const text = getTextFromNodes(mutation.addedNodes);\n if (text) {\n changes.addedText.push(text);\n }\n } else if (mutation.type === 'characterData') {\n changes.charDataChanged = true;\n }\n }\n\n // Emit announcements for each live region that had changes\n for (const [region, changes] of regionChanges) {\n const politeness = getLiveRegionPoliteness(region);\n if (!politeness) continue;\n\n let text: string;\n if (isAtomic(region)) {\n // aria-atomic=\"true\": read the entire region's text content\n text = region.textContent?.trim() || '';\n } else {\n // Non-atomic: only announce changed/added content\n if (changes.addedText.length > 0) {\n text = changes.addedText.join(' ').trim();\n } else if (changes.charDataChanged) {\n // characterData changed but no new nodes — read updated text\n text = region.textContent?.trim() || '';\n } else {\n text = '';\n }\n }\n\n emitAnnouncement(region, text, politeness);\n }\n }\n\n // -------------------------------------------------------------------------\n // Document Mutation Handling (detect new live regions)\n // -------------------------------------------------------------------------\n\n /**\n * Handle document-level mutations to detect new live regions being added.\n */\n function handleDocumentMutations(mutations: MutationRecord[]): void {\n for (const mutation of mutations) {\n if (mutation.type !== 'childList') continue;\n\n mutation.addedNodes.forEach((node) => {\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const element = node as Element;\n\n // Check if the added element itself is a live region\n if (getLiveRegionPoliteness(element) !== null && !trackedRegions.has(element)) {\n trackRegion(element);\n }\n\n // Check descendants for live regions\n const descendants = element.querySelectorAll('[aria-live], [role]');\n descendants.forEach((desc) => {\n if (getLiveRegionPoliteness(desc) !== null && !trackedRegions.has(desc)) {\n trackRegion(desc);\n }\n });\n });\n\n // Handle removed nodes: untrack regions that are removed from DOM\n mutation.removedNodes.forEach((node) => {\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const element = node as Element;\n\n if (trackedRegions.has(element)) {\n trackedRegions.delete(element);\n }\n\n // Remove descendants\n const descendants = element.querySelectorAll('[aria-live], [role]');\n descendants.forEach((desc) => {\n trackedRegions.delete(desc);\n });\n });\n }\n }\n\n /**\n * Track a new live region element.\n */\n function trackRegion(element: Element): void {\n trackedRegions.add(element);\n }\n\n // -------------------------------------------------------------------------\n // Discovery\n // -------------------------------------------------------------------------\n\n /**\n * Find all existing live regions in the document and start tracking them.\n */\n function discoverExistingRegions(): void {\n // Elements with explicit aria-live\n const ariaLiveElements = document.querySelectorAll('[aria-live]');\n ariaLiveElements.forEach((el) => {\n if (getLiveRegionPoliteness(el) !== null) {\n trackRegion(el);\n }\n });\n\n // Elements with implicit live region roles\n IMPLICIT_LIVE_ROLES.forEach((role) => {\n const roleElements = document.querySelectorAll(`[role=\"${role}\"]`);\n roleElements.forEach((el) => {\n if (!trackedRegions.has(el)) {\n trackRegion(el);\n }\n });\n });\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n function start(): void {\n // Discover existing live regions\n discoverExistingRegions();\n\n // Set up content observer for changes within live regions\n contentObserver = new MutationObserver(handleContentMutations);\n\n // Observe the entire document body for childList and characterData changes\n // in subtrees. We filter by live region ancestry in the handler.\n const body = document.body;\n if (body) {\n contentObserver.observe(body, {\n childList: true,\n characterData: true,\n subtree: true,\n characterDataOldValue: true,\n });\n }\n\n // Set up document observer for detecting new live regions being added\n documentObserver = new MutationObserver(handleDocumentMutations);\n if (body) {\n documentObserver.observe(body, {\n childList: true,\n subtree: true,\n });\n }\n }\n\n function stop(): void {\n if (contentObserver) {\n contentObserver.disconnect();\n contentObserver = null;\n }\n if (documentObserver) {\n documentObserver.disconnect();\n documentObserver = null;\n }\n trackedRegions.clear();\n }\n\n return { start, stop };\n}\n","/**\n * Dialog Observer\n *\n * Observes dialog open/close events on a document and emits DIALOG_OPENED\n * and DIALOG_CLOSED accessibility events. Tracks:\n * - Native `<dialog>` elements gaining/losing the `open` attribute\n * - Elements with role=\"dialog\" or role=\"alertdialog\" being added to the DOM\n * or having aria-modal change\n *\n * Maintains an internal stack of open dialogs for use by the heuristic\n * warnings module.\n *\n * @module runtime/observers/dialog-observer\n */\n\nimport type { AccessibilityEvent, EventTarget as A11yEventTarget } from '../types';\nimport { generateSelector } from '../selector';\n\n// ---------------------------------------------------------------------------\n// Accessible Name Computation (self-contained, dialog-aware)\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the accessible name for a dialog element.\n * Checks aria-label, then aria-labelledby, then title attribute,\n * then falls back to the first heading's textContent within the dialog.\n */\nfunction computeDialogAccessibleName(element: Element, document: Document): string {\n // 1. aria-label takes precedence\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n // 2. aria-labelledby: resolve referenced element(s) text content\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy && labelledBy.trim()) {\n const ids = labelledBy.trim().split(/\\s+/);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = document.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n const combined = parts.join(' ');\n if (combined) {\n return combined;\n }\n }\n\n // 3. title attribute\n const title = element.getAttribute('title');\n if (title && title.trim()) {\n return title.trim();\n }\n\n // 4. First heading within the dialog\n const heading = element.querySelector('h1, h2, h3, h4, h5, h6');\n if (heading && heading.textContent && heading.textContent.trim()) {\n return heading.textContent.trim();\n }\n\n return '';\n}\n\n// ---------------------------------------------------------------------------\n// Role Resolution\n// ---------------------------------------------------------------------------\n\n/**\n * Determine the role of a dialog element.\n * Returns the explicit role attribute value, or 'dialog' for native <dialog>.\n */\nfunction getDialogRole(element: Element): string {\n const explicitRole = element.getAttribute('role');\n if (explicitRole && explicitRole.trim()) {\n return explicitRole.trim();\n }\n\n if (element.tagName.toLowerCase() === 'dialog') {\n return 'dialog';\n }\n\n return 'generic';\n}\n\n// ---------------------------------------------------------------------------\n// Dialog Detection Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Check if an element is a dialog (native <dialog> or role=\"dialog\" / role=\"alertdialog\").\n */\nfunction isDialogElement(element: Element): boolean {\n if (element.tagName.toLowerCase() === 'dialog') {\n return true;\n }\n const role = element.getAttribute('role');\n return role === 'dialog' || role === 'alertdialog';\n}\n\n/**\n * Determine if a dialog is modal.\n * A dialog is modal if:\n * - It's a native <dialog> opened via showModal() (has the `open` attribute and is the top layer)\n * - It has aria-modal=\"true\"\n */\nfunction isDialogModal(element: Element): boolean {\n const ariaModal = element.getAttribute('aria-modal');\n if (ariaModal === 'true') {\n return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Dialog Observer\n// ---------------------------------------------------------------------------\n\n/** Callback type for emitting accessibility events from the observer. */\nexport type DialogEventEmitter = (event: AccessibilityEvent) => void;\n\nexport interface DialogObserverOptions {\n /** The document to observe dialog events on */\n document: Document;\n /** Callback to emit accessibility events */\n onEvent: DialogEventEmitter;\n /** Function to get the current timestamp (ms since session start) */\n getTimestamp: () => number;\n}\n\nexport interface DialogObserver {\n /** Start observing dialog open/close events */\n start(): void;\n /** Stop observing dialog events */\n stop(): void;\n /** Whether the observer is currently active */\n readonly isActive: boolean;\n /** Get the current stack of open dialog names */\n getOpenDialogs(): string[];\n}\n\n/** Internal representation of a tracked open dialog */\ninterface TrackedDialog {\n element: Element;\n name: string;\n selector: string;\n}\n\n/**\n * Creates a DialogObserver that watches for dialog open/close events\n * and emits DIALOG_OPENED / DIALOG_CLOSED accessibility events.\n */\nexport function createDialogObserver(options: DialogObserverOptions): DialogObserver {\n const { document: doc, onEvent, getTimestamp } = options;\n\n let active = false;\n let mutationObserver: MutationObserver | null = null;\n const openDialogStack: TrackedDialog[] = [];\n\n function buildEventTarget(element: Element): A11yEventTarget {\n return {\n role: getDialogRole(element),\n accessibleName: computeDialogAccessibleName(element, doc),\n selector: generateSelector(element),\n };\n }\n\n function emitDialogOpened(element: Element): void {\n const name = computeDialogAccessibleName(element, doc);\n const isModal = isDialogModal(element);\n const target = buildEventTarget(element);\n\n // Add to open dialog stack\n openDialogStack.push({\n element,\n name,\n selector: target.selector,\n });\n\n const a11yEvent: AccessibilityEvent = {\n type: 'DIALOG_OPENED',\n timestamp: getTimestamp(),\n target,\n payload: {\n kind: 'dialog_opened',\n dialogName: name,\n isModal,\n },\n };\n\n onEvent(a11yEvent);\n }\n\n function emitDialogClosed(element: Element): void {\n const name = computeDialogAccessibleName(element, doc);\n const target = buildEventTarget(element);\n\n // Remove from open dialog stack\n const index = openDialogStack.findIndex((d) => d.element === element);\n if (index !== -1) {\n openDialogStack.splice(index, 1);\n }\n\n const a11yEvent: AccessibilityEvent = {\n type: 'DIALOG_CLOSED',\n timestamp: getTimestamp(),\n target,\n payload: {\n kind: 'dialog_closed',\n dialogName: name,\n },\n };\n\n onEvent(a11yEvent);\n }\n\n function isTrackedAsOpen(element: Element): boolean {\n return openDialogStack.some((d) => d.element === element);\n }\n\n function handleMutations(mutations: MutationRecord[]): void {\n if (!active) return;\n\n for (const mutation of mutations) {\n // Handle attribute changes\n if (mutation.type === 'attributes') {\n const target = mutation.target;\n if (!(target instanceof doc.defaultView!.Element)) continue;\n\n // Native <dialog> open attribute change\n if (\n mutation.attributeName === 'open' &&\n target.tagName.toLowerCase() === 'dialog'\n ) {\n if (target.hasAttribute('open')) {\n // Dialog opened\n if (!isTrackedAsOpen(target)) {\n emitDialogOpened(target);\n }\n } else {\n // Dialog closed\n if (isTrackedAsOpen(target)) {\n emitDialogClosed(target);\n }\n }\n }\n\n // aria-modal change on role=\"dialog\" or role=\"alertdialog\"\n if (mutation.attributeName === 'aria-modal' && isDialogElement(target)) {\n // If the dialog is already tracked, the modal status changed but\n // it's still open - we could emit an update, but per spec we just\n // track open/close. The modal status is captured at open time.\n // If it wasn't tracked and now has aria-modal=\"true\", check visibility.\n if (!isTrackedAsOpen(target) && isVisibleDialog(target)) {\n emitDialogOpened(target);\n }\n }\n\n // role attribute change - element might have become a dialog\n if (mutation.attributeName === 'role') {\n const oldRole = mutation.oldValue;\n const newRole = target.getAttribute('role');\n const wasDialog = oldRole === 'dialog' || oldRole === 'alertdialog';\n const isNowDialog = newRole === 'dialog' || newRole === 'alertdialog';\n\n if (!wasDialog && isNowDialog && isVisibleDialog(target)) {\n emitDialogOpened(target);\n } else if (wasDialog && !isNowDialog && isTrackedAsOpen(target)) {\n emitDialogClosed(target);\n }\n }\n }\n\n // Handle added nodes (role=\"dialog\" elements added to the DOM)\n if (mutation.type === 'childList') {\n for (let i = 0; i < mutation.addedNodes.length; i++) {\n const node = mutation.addedNodes[i];\n if (!(node instanceof doc.defaultView!.Element)) continue;\n\n // Check the added node itself\n if (isDialogElement(node) && isVisibleDialog(node)) {\n if (!isTrackedAsOpen(node)) {\n emitDialogOpened(node);\n }\n }\n\n // Check descendants of the added node\n const dialogDescendants = node.querySelectorAll(\n 'dialog[open], [role=\"dialog\"], [role=\"alertdialog\"]'\n );\n for (let j = 0; j < dialogDescendants.length; j++) {\n const dialog = dialogDescendants[j];\n if (isVisibleDialog(dialog) && !isTrackedAsOpen(dialog)) {\n emitDialogOpened(dialog);\n }\n }\n }\n\n // Handle removed nodes - dialogs removed from DOM\n for (let i = 0; i < mutation.removedNodes.length; i++) {\n const node = mutation.removedNodes[i];\n if (!(node instanceof doc.defaultView!.Element)) continue;\n\n // Check the removed node itself\n if (isTrackedAsOpen(node)) {\n emitDialogClosed(node);\n }\n\n // Check descendants of the removed node\n const trackedInRemoved = openDialogStack.filter((d) =>\n node.contains(d.element)\n );\n for (const tracked of trackedInRemoved) {\n emitDialogClosed(tracked.element);\n }\n }\n }\n }\n }\n\n /**\n * Determine if a dialog element is considered \"visible\" / open.\n * - Native <dialog>: must have `open` attribute\n * - ARIA dialog: considered visible when added to DOM (we can't reliably\n * detect CSS visibility in jsdom, so we assume role=\"dialog\" elements\n * in the DOM are intended to be visible)\n */\n function isVisibleDialog(element: Element): boolean {\n if (element.tagName.toLowerCase() === 'dialog') {\n return element.hasAttribute('open');\n }\n // For ARIA dialogs, we treat presence in the DOM as \"visible\"\n // In a real browser, we'd check computed styles, but jsdom doesn't support that reliably\n return true;\n }\n\n return {\n start(): void {\n if (active) return;\n active = true;\n openDialogStack.length = 0;\n\n // Scan existing open dialogs on start\n const existingDialogs = doc.querySelectorAll(\n 'dialog[open], [role=\"dialog\"], [role=\"alertdialog\"]'\n );\n for (let i = 0; i < existingDialogs.length; i++) {\n const dialog = existingDialogs[i];\n if (isVisibleDialog(dialog)) {\n // Track them without emitting events (they were already open before observation)\n openDialogStack.push({\n element: dialog,\n name: computeDialogAccessibleName(dialog, doc),\n selector: generateSelector(dialog),\n });\n }\n }\n\n // Set up MutationObserver\n mutationObserver = new MutationObserver(handleMutations);\n mutationObserver.observe(doc.body || doc.documentElement, {\n attributes: true,\n attributeFilter: ['open', 'role', 'aria-modal'],\n attributeOldValue: true,\n childList: true,\n subtree: true,\n });\n },\n\n stop(): void {\n if (!active) return;\n active = false;\n\n if (mutationObserver) {\n mutationObserver.disconnect();\n mutationObserver = null;\n }\n\n openDialogStack.length = 0;\n },\n\n get isActive(): boolean {\n return active;\n },\n\n getOpenDialogs(): string[] {\n return openDialogStack.map((d) => d.name);\n },\n };\n}\n","/**\n * Runtime Accessibility Engine\n *\n * Coordinates all accessibility observers (focus, mutation, live region, dialog)\n * into a single engine that collects normalized AccessibilityEvents during\n * component interaction. Events are timestamped relative to session start\n * and stored in chronological order.\n *\n * @module runtime/engine\n */\n\nimport type { AccessibilityEvent } from './types';\nimport { createFocusObserver, type FocusObserver } from './observers/focus-observer';\nimport { createMutationObserver, type AccessibilityMutationObserver } from './observers/mutation-observer';\nimport { createLiveRegionObserver, type LiveRegionObserver } from './observers/live-region-observer';\nimport { createDialogObserver, type DialogObserver } from './observers/dialog-observer';\n\n// ---------------------------------------------------------------------------\n// Engine Options\n// ---------------------------------------------------------------------------\n\nexport interface EngineOptions {\n /** Document to observe */\n document: Document;\n /** Whether to enable heuristic warnings (default: true) */\n heuristics?: boolean;\n /** Custom settle time in ms (default: 100) */\n settleTime?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Engine Interface\n// ---------------------------------------------------------------------------\n\nexport interface RuntimeAccessibilityEngine {\n /** Attach observers to the document and begin event collection */\n attach(): void;\n /** Detach all observers and stop collection */\n detach(): void;\n /** Get all collected events since attach (chronological order) */\n getEvents(): AccessibilityEvent[];\n /** Clear collected events without detaching */\n reset(): void;\n /** Whether the engine is currently attached */\n readonly isAttached: boolean;\n /** Expose dialog observer for heuristics module */\n readonly dialogObserver: { getOpenDialogs(): string[] };\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a RuntimeAccessibilityEngine that coordinates all observers\n * and collects accessibility events with monotonically increasing timestamps.\n */\nexport function createEngine(options: EngineOptions): RuntimeAccessibilityEngine {\n const { document: doc } = options;\n\n let attached = false;\n let sessionStart = 0;\n let events: AccessibilityEvent[] = [];\n\n // Timestamp function: returns ms elapsed since session start\n function getTimestamp(): number {\n return Date.now() - sessionStart;\n }\n\n // Shared event collector for focus, mutation, and dialog observers\n function collectEvent(event: AccessibilityEvent): void {\n events.push(event);\n }\n\n // Live region observer has a different callback signature:\n // it emits events without a timestamp, so we wrap to add one\n function collectLiveRegionEvent(event: Omit<AccessibilityEvent, 'timestamp'>): void {\n const fullEvent: AccessibilityEvent = {\n ...event,\n timestamp: getTimestamp(),\n } as AccessibilityEvent;\n events.push(fullEvent);\n }\n\n // Create all observers\n const focusObs: FocusObserver = createFocusObserver({\n document: doc,\n onEvent: collectEvent,\n getTimestamp,\n });\n\n const mutationObs: AccessibilityMutationObserver = createMutationObserver({\n document: doc,\n onEvent: collectEvent,\n getTimestamp,\n });\n\n const liveRegionObs: LiveRegionObserver = createLiveRegionObserver(\n doc,\n collectLiveRegionEvent\n );\n\n const dialogObs: DialogObserver = createDialogObserver({\n document: doc,\n onEvent: collectEvent,\n getTimestamp,\n });\n\n return {\n attach(): void {\n if (attached) return;\n attached = true;\n sessionStart = Date.now();\n events = [];\n\n // Start all observers\n focusObs.start();\n mutationObs.start();\n liveRegionObs.start();\n dialogObs.start();\n },\n\n detach(): void {\n if (!attached) return;\n attached = false;\n\n // Stop all observers\n focusObs.stop();\n mutationObs.stop();\n liveRegionObs.stop();\n dialogObs.stop();\n },\n\n getEvents(): AccessibilityEvent[] {\n // Events are already in chronological order due to single-threaded execution\n return [...events];\n },\n\n reset(): void {\n events = [];\n },\n\n get isAttached(): boolean {\n return attached;\n },\n\n get dialogObserver(): { getOpenDialogs(): string[] } {\n return {\n getOpenDialogs(): string[] {\n return dialogObs.getOpenDialogs();\n },\n };\n },\n };\n}\n","/**\n * Interaction Execution\n *\n * Executes interaction sequences against a document, dispatching proper\n * DOM events (keyboard, mouse, focus) and emitting KEYBOARD_ACTION\n * accessibility events for each action.\n *\n * @module runtime/interactions\n */\n\nimport type { InteractionAction, InteractionSequence, AccessibilityEvent } from './types';\nimport { generateSelector } from './selector';\n\n// ---------------------------------------------------------------------------\n// Key Mappings\n// ---------------------------------------------------------------------------\n\ninterface KeyInfo {\n key: string;\n code: string;\n keyCode: number;\n}\n\nconst KEY_MAP: Record<string, KeyInfo> = {\n Tab: { key: 'Tab', code: 'Tab', keyCode: 9 },\n Escape: { key: 'Escape', code: 'Escape', keyCode: 27 },\n Enter: { key: 'Enter', code: 'Enter', keyCode: 13 },\n ' ': { key: ' ', code: 'Space', keyCode: 32 },\n ArrowUp: { key: 'ArrowUp', code: 'ArrowUp', keyCode: 38 },\n ArrowDown: { key: 'ArrowDown', code: 'ArrowDown', keyCode: 40 },\n ArrowLeft: { key: 'ArrowLeft', code: 'ArrowLeft', keyCode: 37 },\n ArrowRight: { key: 'ArrowRight', code: 'ArrowRight', keyCode: 39 },\n};\n\n// ---------------------------------------------------------------------------\n// Focusable Element Detection\n// ---------------------------------------------------------------------------\n\nconst FOCUSABLE_SELECTOR = [\n 'button:not([disabled])',\n 'a[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ');\n\n/**\n * Get all focusable elements in DOM order, excluding those with tabindex=\"-1\".\n */\nfunction getFocusableElements(document: Document): Element[] {\n return Array.from(document.querySelectorAll(FOCUSABLE_SELECTOR));\n}\n\n// ---------------------------------------------------------------------------\n// Accessible Name and Role (lightweight versions for event target)\n// ---------------------------------------------------------------------------\n\nfunction computeAccessibleName(element: Element, document: Document): string {\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy && labelledBy.trim()) {\n const ids = labelledBy.trim().split(/\\s+/);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = document.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n const combined = parts.join(' ');\n if (combined) return combined;\n }\n\n const textContent = element.textContent;\n if (textContent && textContent.trim()) {\n return textContent.trim();\n }\n\n return '';\n}\n\nfunction getElementRole(element: Element): string {\n const explicitRole = element.getAttribute('role');\n if (explicitRole && explicitRole.trim()) {\n return explicitRole.trim();\n }\n\n const tagName = element.tagName.toLowerCase();\n switch (tagName) {\n case 'button':\n return 'button';\n case 'a':\n return element.hasAttribute('href') ? 'link' : 'generic';\n case 'input': {\n const type = (element.getAttribute('type') || 'text').toLowerCase();\n switch (type) {\n case 'button':\n case 'submit':\n case 'reset':\n case 'image':\n return 'button';\n case 'checkbox':\n return 'checkbox';\n case 'radio':\n return 'radio';\n case 'range':\n return 'slider';\n case 'search':\n return 'searchbox';\n default:\n return 'textbox';\n }\n }\n case 'textarea':\n return 'textbox';\n case 'select':\n return element.hasAttribute('multiple') ? 'listbox' : 'combobox';\n case 'dialog':\n return 'dialog';\n default:\n return 'generic';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Event Target Builder\n// ---------------------------------------------------------------------------\n\nfunction buildEventTarget(element: Element, document: Document) {\n return {\n role: getElementRole(element),\n accessibleName: computeAccessibleName(element, document),\n selector: generateSelector(element),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Keyboard Event Dispatching\n// ---------------------------------------------------------------------------\n\ninterface KeyboardEventOptions {\n key: string;\n code: string;\n keyCode: number;\n shiftKey?: boolean;\n ctrlKey?: boolean;\n altKey?: boolean;\n metaKey?: boolean;\n}\n\n/**\n * Dispatch a full keyboard event sequence (keydown, keypress, keyup)\n * on the currently focused element.\n */\nfunction dispatchKeyboardEvent(\n document: Document,\n options: KeyboardEventOptions\n): void {\n const target = document.activeElement || document.body;\n\n const commonProps = {\n key: options.key,\n code: options.code,\n keyCode: options.keyCode,\n which: options.keyCode,\n shiftKey: options.shiftKey || false,\n ctrlKey: options.ctrlKey || false,\n altKey: options.altKey || false,\n metaKey: options.metaKey || false,\n bubbles: true,\n cancelable: true,\n };\n\n target.dispatchEvent(new KeyboardEvent('keydown', commonProps));\n // keypress is deprecated but still dispatched for compatibility\n // Only dispatch keypress for printable characters\n if (options.key.length === 1) {\n target.dispatchEvent(new KeyboardEvent('keypress', commonProps));\n }\n target.dispatchEvent(new KeyboardEvent('keyup', commonProps));\n}\n\n// ---------------------------------------------------------------------------\n// Key Combo Parsing\n// ---------------------------------------------------------------------------\n\ninterface ParsedCombo {\n key: string;\n modifiers: string[];\n shiftKey: boolean;\n ctrlKey: boolean;\n altKey: boolean;\n metaKey: boolean;\n}\n\n/**\n * Parse a key combination string like \"Control+Shift+A\" into its parts.\n */\nfunction parseKeyCombo(combo: string): ParsedCombo {\n const parts = combo.split('+');\n const modifiers: string[] = [];\n let shiftKey = false;\n let ctrlKey = false;\n let altKey = false;\n let metaKey = false;\n\n // The last part is the key, everything else is a modifier\n const key = parts[parts.length - 1];\n\n for (let i = 0; i < parts.length - 1; i++) {\n const mod = parts[i].toLowerCase();\n switch (mod) {\n case 'shift':\n shiftKey = true;\n modifiers.push('Shift');\n break;\n case 'control':\n case 'ctrl':\n ctrlKey = true;\n modifiers.push('Control');\n break;\n case 'alt':\n altKey = true;\n modifiers.push('Alt');\n break;\n case 'meta':\n case 'cmd':\n case 'command':\n metaKey = true;\n modifiers.push('Meta');\n break;\n }\n }\n\n return { key, modifiers, shiftKey, ctrlKey, altKey, metaKey };\n}\n\n/**\n * Get KeyInfo for a key string. Falls back to generating info from the key name.\n */\nfunction getKeyInfo(key: string): KeyInfo {\n if (KEY_MAP[key]) {\n return KEY_MAP[key];\n }\n // For single character keys\n if (key.length === 1) {\n return {\n key,\n code: `Key${key.toUpperCase()}`,\n keyCode: key.toUpperCase().charCodeAt(0),\n };\n }\n // For other named keys\n return {\n key,\n code: key,\n keyCode: 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Action Executors\n// ---------------------------------------------------------------------------\n\n/**\n * Execute a click action on the element matching the selector.\n * Dispatches mousedown, mouseup, click events, and focuses the element.\n * If the element is not found, emits a WARNING event and continues.\n */\nfunction executeClick(\n selector: string,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const element = document.querySelector(selector);\n\n if (!element) {\n // Emit WARNING for missing element\n const warningEvent: AccessibilityEvent = {\n type: 'WARNING',\n timestamp: getTimestamp(),\n target: {\n role: 'generic',\n accessibleName: '',\n selector: selector,\n },\n payload: {\n kind: 'warning',\n message: `Element not found: ${selector}`,\n },\n };\n onEvent(warningEvent);\n return;\n }\n\n const eventProps = { bubbles: true, cancelable: true };\n\n element.dispatchEvent(new MouseEvent('mousedown', eventProps));\n element.dispatchEvent(new MouseEvent('mouseup', eventProps));\n element.dispatchEvent(new MouseEvent('click', eventProps));\n\n // Focus the element if it's focusable\n if ('focus' in element && typeof (element as HTMLElement).focus === 'function') {\n (element as HTMLElement).focus();\n }\n}\n\n/**\n * Execute a tab action: move focus to the next focusable element.\n */\nfunction executeTab(\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const focusableElements = getFocusableElements(document);\n if (focusableElements.length === 0) return;\n\n const activeElement = document.activeElement;\n let currentIndex = -1;\n\n if (activeElement) {\n currentIndex = focusableElements.indexOf(activeElement);\n }\n\n // Move to next, wrapping around\n const nextIndex = (currentIndex + 1) % focusableElements.length;\n const nextElement = focusableElements[nextIndex] as HTMLElement;\n\n // Dispatch keyboard event on current element\n dispatchKeyboardEvent(document, {\n ...KEY_MAP['Tab'],\n shiftKey: false,\n });\n\n // Move focus\n if (nextElement && typeof nextElement.focus === 'function') {\n nextElement.focus();\n }\n\n // Emit KEYBOARD_ACTION event\n const target = document.activeElement || document.body;\n const keyboardEvent: AccessibilityEvent = {\n type: 'KEYBOARD_ACTION',\n timestamp: getTimestamp(),\n target: buildEventTarget(target as Element, document),\n payload: {\n kind: 'keyboard_action',\n key: 'Tab',\n modifiers: [],\n },\n };\n onEvent(keyboardEvent);\n}\n\n/**\n * Execute a shift+tab action: move focus to the previous focusable element.\n */\nfunction executeShiftTab(\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const focusableElements = getFocusableElements(document);\n if (focusableElements.length === 0) return;\n\n const activeElement = document.activeElement;\n let currentIndex = -1;\n\n if (activeElement) {\n currentIndex = focusableElements.indexOf(activeElement);\n }\n\n // Move to previous, wrapping around\n const prevIndex = currentIndex <= 0 ? focusableElements.length - 1 : currentIndex - 1;\n const prevElement = focusableElements[prevIndex] as HTMLElement;\n\n // Dispatch keyboard event on current element\n dispatchKeyboardEvent(document, {\n ...KEY_MAP['Tab'],\n shiftKey: true,\n });\n\n // Move focus\n if (prevElement && typeof prevElement.focus === 'function') {\n prevElement.focus();\n }\n\n // Emit KEYBOARD_ACTION event\n const target = document.activeElement || document.body;\n const keyboardEvent: AccessibilityEvent = {\n type: 'KEYBOARD_ACTION',\n timestamp: getTimestamp(),\n target: buildEventTarget(target as Element, document),\n payload: {\n kind: 'keyboard_action',\n key: 'Tab',\n modifiers: ['Shift'],\n },\n };\n onEvent(keyboardEvent);\n}\n\n/**\n * Execute a simple keyboard action (escape, enter, space, arrow keys).\n */\nfunction executeKeyAction(\n keyName: string,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const keyInfo = KEY_MAP[keyName];\n if (!keyInfo) return;\n\n dispatchKeyboardEvent(document, {\n ...keyInfo,\n });\n\n // Emit KEYBOARD_ACTION event\n const target = document.activeElement || document.body;\n const keyboardEvent: AccessibilityEvent = {\n type: 'KEYBOARD_ACTION',\n timestamp: getTimestamp(),\n target: buildEventTarget(target as Element, document),\n payload: {\n kind: 'keyboard_action',\n key: keyName,\n modifiers: [],\n },\n };\n onEvent(keyboardEvent);\n}\n\n/**\n * Execute a custom key combination (e.g., \"Control+A\", \"Shift+Tab\").\n */\nfunction executeKeyCombo(\n combo: string,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const parsed = parseKeyCombo(combo);\n const keyInfo = getKeyInfo(parsed.key);\n\n dispatchKeyboardEvent(document, {\n ...keyInfo,\n shiftKey: parsed.shiftKey,\n ctrlKey: parsed.ctrlKey,\n altKey: parsed.altKey,\n metaKey: parsed.metaKey,\n });\n\n // Emit KEYBOARD_ACTION event\n const target = document.activeElement || document.body;\n const keyboardEvent: AccessibilityEvent = {\n type: 'KEYBOARD_ACTION',\n timestamp: getTimestamp(),\n target: buildEventTarget(target as Element, document),\n payload: {\n kind: 'keyboard_action',\n key: parsed.key,\n modifiers: parsed.modifiers,\n },\n };\n onEvent(keyboardEvent);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Execute a single interaction action against the document.\n *\n * For keyboard actions, dispatches proper KeyboardEvent sequences (keydown, keypress, keyup).\n * For tab/shiftTab, computes next/previous focusable element and moves focus.\n * Emits KEYBOARD_ACTION events for each keyboard action.\n * Handles missing elements by emitting WARNING events and continuing.\n *\n * Click and wait actions do not emit KEYBOARD_ACTION events.\n */\nexport async function executeAction(\n action: InteractionAction,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): Promise<void> {\n switch (action.type) {\n case 'click':\n executeClick(action.selector, document, onEvent, getTimestamp);\n break;\n\n case 'tab':\n executeTab(document, onEvent, getTimestamp);\n break;\n\n case 'shiftTab':\n executeShiftTab(document, onEvent, getTimestamp);\n break;\n\n case 'escape':\n executeKeyAction('Escape', document, onEvent, getTimestamp);\n break;\n\n case 'enter':\n executeKeyAction('Enter', document, onEvent, getTimestamp);\n break;\n\n case 'space':\n executeKeyAction(' ', document, onEvent, getTimestamp);\n break;\n\n case 'arrowUp':\n executeKeyAction('ArrowUp', document, onEvent, getTimestamp);\n break;\n\n case 'arrowDown':\n executeKeyAction('ArrowDown', document, onEvent, getTimestamp);\n break;\n\n case 'arrowLeft':\n executeKeyAction('ArrowLeft', document, onEvent, getTimestamp);\n break;\n\n case 'arrowRight':\n executeKeyAction('ArrowRight', document, onEvent, getTimestamp);\n break;\n\n case 'key':\n executeKeyCombo(action.combo, document, onEvent, getTimestamp);\n break;\n\n case 'wait':\n // Wait does not emit any events\n await new Promise((resolve) => setTimeout(resolve, action.ms));\n break;\n }\n}\n\n/**\n * Execute an interaction sequence in order, with DOM stability waits between actions.\n *\n * Runs each action sequentially, waiting for `settleTime` milliseconds between actions\n * to allow the DOM to stabilize. This ensures observers can capture resulting changes\n * before the next action fires.\n *\n * @param sequence - The interaction sequence to execute\n * @param document - The target document\n * @param onEvent - Callback to emit accessibility events\n * @param getTimestamp - Function returning current timestamp in ms since session start\n * @param settleTime - Milliseconds to wait between actions for DOM stability (default: 100)\n */\nexport async function executeSequence(\n sequence: InteractionSequence,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number,\n settleTime: number = 100\n): Promise<void> {\n for (let i = 0; i < sequence.actions.length; i++) {\n const action = sequence.actions[i];\n\n await executeAction(action, document, onEvent, getTimestamp);\n\n // Wait for DOM stability between actions (except after the last action)\n if (i < sequence.actions.length - 1) {\n await new Promise((resolve) => setTimeout(resolve, settleTime));\n }\n }\n}\n","/**\n * Heuristic Warning Analyzer\n *\n * Processes accessibility events one at a time and emits WARNING events\n * when common runtime accessibility anti-patterns are detected. Operates\n * independently of baselines, providing value from the first run.\n *\n * Detected patterns:\n * - Focus not moved into modal dialog within configured timeout (default: 100ms)\n * - Focus escaped modal dialog (focus moved to element outside open dialog)\n * - Rapid announcements (too many in a short window)\n * - Keyboard action with no accessibility response within timeout\n * - Focused element removed from DOM without explicit focus management\n *\n * Uses event timestamps (not real-time timers) for timeout detection,\n * enabling deterministic testing with jsdom.\n *\n * @module runtime/heuristics\n */\n\nimport type {\n AccessibilityEvent,\n EventTarget as A11yEventTarget,\n DialogOpenedPayload,\n WarningPayload,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// Configuration\n// ---------------------------------------------------------------------------\n\n/**\n * Configuration for heuristic warning thresholds.\n */\nexport interface HeuristicConfig {\n /** Time window to detect focus moving into dialog (default: 100ms) */\n dialogFocusTimeout: number;\n /** Time window to detect rapid announcements (default: 500ms) */\n rapidAnnouncementWindow: number;\n /** Threshold for rapid announcement count (default: 3) */\n rapidAnnouncementThreshold: number;\n /** Time window to detect keyboard action response (default: 200ms) */\n keyboardResponseTimeout: number;\n}\n\nconst DEFAULT_CONFIG: HeuristicConfig = {\n dialogFocusTimeout: 100,\n rapidAnnouncementWindow: 500,\n rapidAnnouncementThreshold: 3,\n keyboardResponseTimeout: 200,\n};\n\n// ---------------------------------------------------------------------------\n// Internal State Types\n// ---------------------------------------------------------------------------\n\n/** Tracks a pending dialog focus check */\ninterface PendingDialogFocus {\n /** Selector of the dialog that opened */\n dialogSelector: string;\n /** Name of the dialog for warning messages */\n dialogName: string;\n /** Timestamp when the dialog was opened */\n openedAt: number;\n /** Whether this dialog is modal */\n isModal: boolean;\n /** Whether focus has been moved into the dialog */\n resolved: boolean;\n}\n\n/** Tracks a pending keyboard response check */\ninterface PendingKeyboardResponse {\n /** The keyboard action event that started the check */\n event: AccessibilityEvent;\n /** Timestamp when the keyboard action occurred */\n timestamp: number;\n /** Whether an accessibility response has been received */\n resolved: boolean;\n}\n\n/** Tracks an open dialog for focus escape detection */\ninterface TrackedDialog {\n /** CSS selector of the dialog container */\n selector: string;\n /** Accessible name of the dialog */\n name: string;\n /** Whether this is a modal dialog */\n isModal: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Heuristic Analyzer Interface\n// ---------------------------------------------------------------------------\n\n/**\n * Processes accessibility events and detects runtime anti-patterns.\n */\nexport interface HeuristicAnalyzer {\n /** Process an event and return any warnings it triggers */\n process(event: AccessibilityEvent): AccessibilityEvent[];\n /** Get current open dialog selectors (for focus escape detection) */\n readonly openDialogs: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a heuristic analyzer that processes accessibility events and\n * emits warnings when common anti-patterns are detected.\n *\n * The analyzer uses event timestamps for timeout detection rather than\n * real-time timers, making it deterministic and testable with jsdom.\n */\nexport function createHeuristicAnalyzer(\n config?: Partial<HeuristicConfig>\n): HeuristicAnalyzer {\n const cfg: HeuristicConfig = { ...DEFAULT_CONFIG, ...config };\n\n // Internal state\n const trackedDialogs: TrackedDialog[] = [];\n const pendingDialogFocusChecks: PendingDialogFocus[] = [];\n const pendingKeyboardResponses: PendingKeyboardResponse[] = [];\n const announcementTimestamps: number[] = [];\n\n // Track the last known focused element selector for DOM removal detection\n let lastFocusedSelector: string | null = null;\n\n // ---------------------------------------------------------------------------\n // Helper: Create a WARNING event\n // ---------------------------------------------------------------------------\n\n function createWarning(\n timestamp: number,\n message: string,\n target: A11yEventTarget,\n relatedEvent?: AccessibilityEvent\n ): AccessibilityEvent {\n const payload: WarningPayload = {\n kind: 'warning',\n message,\n relatedEvent,\n };\n\n return {\n type: 'WARNING',\n timestamp,\n target,\n payload,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Check: Dialog focus timeout expired\n // ---------------------------------------------------------------------------\n\n function checkExpiredDialogFocusTimeouts(\n currentTimestamp: number\n ): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n for (let i = pendingDialogFocusChecks.length - 1; i >= 0; i--) {\n const pending = pendingDialogFocusChecks[i];\n if (pending.resolved) continue;\n\n const elapsed = currentTimestamp - pending.openedAt;\n if (elapsed > cfg.dialogFocusTimeout) {\n // Only emit warning for modal dialogs\n if (pending.isModal) {\n warnings.push(\n createWarning(\n currentTimestamp,\n 'Focus was not moved into modal dialog',\n {\n role: 'dialog',\n accessibleName: pending.dialogName,\n selector: pending.dialogSelector,\n }\n )\n );\n }\n // Mark as resolved (expired) to avoid duplicate warnings\n pending.resolved = true;\n }\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Check: Keyboard response timeout expired\n // ---------------------------------------------------------------------------\n\n function checkExpiredKeyboardResponses(\n currentTimestamp: number\n ): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n for (let i = pendingKeyboardResponses.length - 1; i >= 0; i--) {\n const pending = pendingKeyboardResponses[i];\n if (pending.resolved) continue;\n\n const elapsed = currentTimestamp - pending.timestamp;\n if (elapsed > cfg.keyboardResponseTimeout) {\n warnings.push(\n createWarning(\n currentTimestamp,\n 'Keyboard action produced no accessibility response',\n pending.event.target,\n pending.event\n )\n );\n pending.resolved = true;\n }\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Check: Rapid announcements\n // ---------------------------------------------------------------------------\n\n function checkRapidAnnouncements(\n currentTimestamp: number\n ): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n // Remove old timestamps outside the window\n const windowStart = currentTimestamp - cfg.rapidAnnouncementWindow;\n while (announcementTimestamps.length > 0 && announcementTimestamps[0] < windowStart) {\n announcementTimestamps.shift();\n }\n\n // Check if threshold exceeded\n if (announcementTimestamps.length > cfg.rapidAnnouncementThreshold) {\n warnings.push(\n createWarning(\n currentTimestamp,\n 'Rapid announcements detected: assistive technology users may miss content',\n {\n role: 'region',\n accessibleName: '',\n selector: 'body',\n }\n )\n );\n\n // Clear timestamps to avoid repeated warnings for the same burst\n announcementTimestamps.length = 0;\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Check: Focus escape from modal dialog\n // ---------------------------------------------------------------------------\n\n function checkFocusEscape(event: AccessibilityEvent): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n if (event.type !== 'FOCUS_CHANGED') return warnings;\n\n // Only check if there are open modal dialogs\n const modalDialogs = trackedDialogs.filter((d) => d.isModal);\n if (modalDialogs.length === 0) return warnings;\n\n const focusedSelector = event.target.selector;\n\n // Check if the focused element is outside all open modal dialogs\n for (const dialog of modalDialogs) {\n // Focus is outside the dialog if the focused element's selector\n // does not start with/contain the dialog's selector\n if (!isSelectorInside(focusedSelector, dialog.selector)) {\n warnings.push(\n createWarning(\n event.timestamp,\n 'Focus escaped modal dialog',\n event.target,\n event\n )\n );\n break; // One warning is enough\n }\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Check: Focused element removed from DOM\n // ---------------------------------------------------------------------------\n\n function checkFocusedElementRemoved(\n event: AccessibilityEvent\n ): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n // DOM_MUTATION events where the target matches the last focused element\n // indicate the focused element may have been removed\n if (event.type === 'DOM_MUTATION' && lastFocusedSelector !== null) {\n if (event.target.selector === lastFocusedSelector) {\n warnings.push(\n createWarning(\n event.timestamp,\n 'Focused element removed without focus management',\n event.target,\n event\n )\n );\n }\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Selector Containment Check\n // ---------------------------------------------------------------------------\n\n /**\n * Determines if `childSelector` represents an element inside the container\n * identified by `containerSelector`.\n *\n * Uses a simple heuristic: the child selector starts with the container\n * selector followed by a combinator (space, >, ~, +).\n */\n function isSelectorInside(\n childSelector: string,\n containerSelector: string\n ): boolean {\n // Direct match - element IS the container\n if (childSelector === containerSelector) return true;\n\n // Child selector starts with container selector path\n // e.g., container is \"#modal\" and child is \"#modal > .content > button\"\n if (childSelector.startsWith(containerSelector + ' ')) return true;\n if (childSelector.startsWith(containerSelector + ' > ')) return true;\n\n // Handle nth-child and descendant patterns\n // e.g., container is \"body > div:nth-child(2)\" and child is \"body > div:nth-child(2) > button\"\n if (childSelector.startsWith(containerSelector + '>')) return true;\n\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // Event Processing\n // ---------------------------------------------------------------------------\n\n function processEvent(event: AccessibilityEvent): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n // First, check for timeouts that may have expired given the current timestamp\n warnings.push(...checkExpiredDialogFocusTimeouts(event.timestamp));\n warnings.push(...checkExpiredKeyboardResponses(event.timestamp));\n\n // Process the event based on its type\n switch (event.type) {\n case 'DIALOG_OPENED': {\n const payload = event.payload as DialogOpenedPayload;\n const dialog: TrackedDialog = {\n selector: event.target.selector,\n name: payload.dialogName,\n isModal: payload.isModal,\n };\n trackedDialogs.push(dialog);\n\n // Set up pending focus check for modal dialogs\n if (payload.isModal) {\n pendingDialogFocusChecks.push({\n dialogSelector: event.target.selector,\n dialogName: payload.dialogName,\n openedAt: event.timestamp,\n isModal: true,\n resolved: false,\n });\n }\n break;\n }\n\n case 'DIALOG_CLOSED': {\n // Remove the dialog from tracked list\n const closedSelector = event.target.selector;\n const idx = trackedDialogs.findIndex(\n (d) => d.selector === closedSelector\n );\n if (idx !== -1) {\n trackedDialogs.splice(idx, 1);\n }\n\n // Resolve any pending focus checks for this dialog\n for (const pending of pendingDialogFocusChecks) {\n if (pending.dialogSelector === closedSelector && !pending.resolved) {\n pending.resolved = true;\n }\n }\n break;\n }\n\n case 'FOCUS_CHANGED': {\n // Resolve pending dialog focus checks if focus moved into dialog\n for (const pending of pendingDialogFocusChecks) {\n if (pending.resolved) continue;\n if (isSelectorInside(event.target.selector, pending.dialogSelector)) {\n pending.resolved = true;\n }\n }\n\n // Resolve pending keyboard responses (focus change is an accessibility response)\n for (const pending of pendingKeyboardResponses) {\n if (!pending.resolved) {\n pending.resolved = true;\n }\n }\n\n // Check for focus escaping modal dialogs\n warnings.push(...checkFocusEscape(event));\n\n // Update last focused element\n lastFocusedSelector = event.target.selector;\n break;\n }\n\n case 'ANNOUNCEMENT': {\n // Track timestamp for rapid announcement detection\n announcementTimestamps.push(event.timestamp);\n\n // Resolve pending keyboard responses (announcement is an accessibility response)\n for (const pending of pendingKeyboardResponses) {\n if (!pending.resolved) {\n pending.resolved = true;\n }\n }\n\n // Check for rapid announcements\n warnings.push(...checkRapidAnnouncements(event.timestamp));\n break;\n }\n\n case 'KEYBOARD_ACTION': {\n // Register pending keyboard response check\n pendingKeyboardResponses.push({\n event,\n timestamp: event.timestamp,\n resolved: false,\n });\n break;\n }\n\n case 'DOM_MUTATION': {\n // Check if the focused element was removed\n warnings.push(...checkFocusedElementRemoved(event));\n\n // DOM mutation is an accessibility response to keyboard action\n for (const pending of pendingKeyboardResponses) {\n if (!pending.resolved) {\n pending.resolved = true;\n }\n }\n break;\n }\n\n case 'STATE_CHANGED':\n case 'ROLE_CHANGED':\n case 'ACCESSIBLE_NAME_CHANGED': {\n // These are all accessibility responses to keyboard actions\n for (const pending of pendingKeyboardResponses) {\n if (!pending.resolved) {\n pending.resolved = true;\n }\n }\n break;\n }\n\n default:\n // WARNING, REGRESSION, and other event types don't trigger heuristics\n break;\n }\n\n // Clean up resolved pending checks to prevent unbounded memory growth\n cleanupResolvedChecks();\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Cleanup\n // ---------------------------------------------------------------------------\n\n function cleanupResolvedChecks(): void {\n // Remove resolved pending checks\n for (let i = pendingDialogFocusChecks.length - 1; i >= 0; i--) {\n if (pendingDialogFocusChecks[i].resolved) {\n pendingDialogFocusChecks.splice(i, 1);\n }\n }\n\n for (let i = pendingKeyboardResponses.length - 1; i >= 0; i--) {\n if (pendingKeyboardResponses[i].resolved) {\n pendingKeyboardResponses.splice(i, 1);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Public Interface\n // ---------------------------------------------------------------------------\n\n return {\n process(event: AccessibilityEvent): AccessibilityEvent[] {\n return processEvent(event);\n },\n\n get openDialogs(): string[] {\n return trackedDialogs.map((d) => d.selector);\n },\n };\n}\n","/**\n * Timeline Generator\n *\n * Orchestrates interaction sessions by coordinating the RuntimeAccessibilityEngine\n * with interaction execution and heuristic analysis. Produces complete\n * AccessibilityTimeline objects containing ordered events, warnings, and\n * session metadata.\n *\n * @module runtime/timeline-generator\n */\n\nimport type {\n AccessibilityEvent,\n AccessibilityTimeline,\n InteractionSequence,\n TimelineMetadata,\n} from './types';\nimport { createEngine, type RuntimeAccessibilityEngine } from './engine';\nimport { executeSequence } from './interactions';\nimport { createHeuristicAnalyzer, type HeuristicAnalyzer } from './heuristics';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst SPEAKABLE_VERSION = '1.3.0';\nconst TIMELINE_FORMAT_VERSION = '1.0';\nconst DEFAULT_SETTLE_PERIOD = 500;\nconst DEFAULT_LOAD_TIMEOUT = 10000;\nconst DOM_STABILITY_WAIT = 100;\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/**\n * Configuration options for creating a TimelineGenerator.\n */\nexport interface TimelineGeneratorOptions {\n /** Document or iframe to attach to */\n document: Document;\n /** Component name for metadata */\n componentName: string;\n /** Story or variant name for metadata */\n storyName?: string;\n /** Settle period after last action (default: 500ms) */\n settlePeriod?: number;\n /** Maximum wait for document load (default: 10000ms) */\n loadTimeout?: number;\n /** Enable heuristic warnings (default: true) */\n heuristics?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Timeline Generator Interface\n// ---------------------------------------------------------------------------\n\n/**\n * Orchestrates an interaction session and produces an AccessibilityTimeline.\n */\nexport interface TimelineGenerator {\n /** Execute an interaction sequence and produce a timeline */\n capture(sequence: InteractionSequence): Promise<AccessibilityTimeline>;\n /** Abort an in-progress capture */\n abort(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a TimelineGenerator that coordinates the engine, interaction\n * execution, and heuristic analysis to produce accessibility timelines.\n *\n * Usage:\n * ```ts\n * const generator = createTimelineGenerator({\n * document: myDocument,\n * componentName: 'LoginForm',\n * storyName: 'Default',\n * });\n *\n * const timeline = await generator.capture({\n * description: 'Tab through form fields',\n * actions: [{ type: 'tab' }, { type: 'tab' }, { type: 'enter' }],\n * });\n * ```\n */\nexport function createTimelineGenerator(\n options: TimelineGeneratorOptions\n): TimelineGenerator {\n const {\n document: doc,\n componentName,\n storyName,\n settlePeriod = DEFAULT_SETTLE_PERIOD,\n loadTimeout = DEFAULT_LOAD_TIMEOUT,\n heuristics: enableHeuristics = true,\n } = options;\n\n let aborted = false;\n let currentEngine: RuntimeAccessibilityEngine | null = null;\n\n return {\n async capture(sequence: InteractionSequence): Promise<AccessibilityTimeline> {\n aborted = false;\n\n // Wait for document to be ready (body must exist)\n await waitForDocumentReady(doc, loadTimeout);\n\n if (aborted) {\n return buildAbortedTimeline(componentName, storyName, sequence);\n }\n\n // Create engine and attach\n const engine = createEngine({ document: doc });\n currentEngine = engine;\n\n // Create heuristic analyzer if enabled\n const heuristicAnalyzer: HeuristicAnalyzer | null = enableHeuristics\n ? createHeuristicAnalyzer()\n : null;\n\n // Collect interaction-emitted events (KEYBOARD_ACTION, WARNINGs from missing elements)\n // These are not captured by the engine's observers.\n const interactionEvents: AccessibilityEvent[] = [];\n\n const sessionStart = Date.now();\n engine.attach();\n\n if (aborted) {\n engine.detach();\n currentEngine = null;\n return buildAbortedTimeline(componentName, storyName, sequence);\n }\n\n // Timestamp function for interactions\n function getTimestamp(): number {\n return Date.now() - sessionStart;\n }\n\n // Execute the interaction sequence with DOM stability waits\n await executeSequence(\n sequence,\n doc,\n (event: AccessibilityEvent) => {\n interactionEvents.push(event);\n },\n getTimestamp,\n DOM_STABILITY_WAIT\n );\n\n if (aborted) {\n engine.detach();\n currentEngine = null;\n return buildAbortedTimeline(componentName, storyName, sequence);\n }\n\n // Wait the settle period for trailing async events\n await delay(settlePeriod);\n\n // Detach engine and finalize\n engine.detach();\n currentEngine = null;\n\n const duration = Date.now() - sessionStart;\n\n // Merge engine events with interaction events, sorted by timestamp\n const engineEvents = engine.getEvents();\n const allEvents = mergeEvents(engineEvents, interactionEvents);\n\n // Run heuristic analysis on all events if enabled\n if (heuristicAnalyzer) {\n const heuristicWarnings: AccessibilityEvent[] = [];\n for (const event of allEvents) {\n const warnings = heuristicAnalyzer.process(event);\n heuristicWarnings.push(...warnings);\n }\n // Add heuristic warnings to the event stream\n for (const warning of heuristicWarnings) {\n allEvents.push(warning);\n }\n // Re-sort after adding heuristic warnings\n allEvents.sort((a, b) => a.timestamp - b.timestamp);\n }\n\n // Extract all WARNING events for the warnings array\n const allWarnings = allEvents.filter((e) => e.type === 'WARNING');\n\n // Build metadata\n const metadata: TimelineMetadata = {\n capturedAt: new Date().toISOString(),\n speakableVersion: SPEAKABLE_VERSION,\n sourceUrl: getSourceUrl(doc),\n userAgent: getUserAgent(),\n };\n\n // Build and return the AccessibilityTimeline\n const timeline: AccessibilityTimeline = {\n version: TIMELINE_FORMAT_VERSION,\n component: componentName,\n story: storyName || null,\n interactionSequence: sequence.description,\n duration,\n events: allEvents,\n warnings: allWarnings,\n metadata,\n };\n\n return timeline;\n },\n\n abort(): void {\n aborted = true;\n if (currentEngine && currentEngine.isAttached) {\n currentEngine.detach();\n currentEngine = null;\n }\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Wait for the document body to be available, with a timeout.\n * If the document already has a body, resolves immediately.\n */\nasync function waitForDocumentReady(\n doc: Document,\n timeout: number\n): Promise<void> {\n if (doc.body) return;\n\n return new Promise<void>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(\n new Error(\n `Document load timeout (${timeout}ms): ${getSourceUrl(doc)}`\n )\n );\n }, timeout);\n\n // Poll for body availability\n const interval = setInterval(() => {\n if (doc.body) {\n clearTimeout(timeoutId);\n clearInterval(interval);\n resolve();\n }\n }, 50);\n });\n}\n\n/**\n * Merge two event arrays into a single sorted array by timestamp.\n */\nfunction mergeEvents(\n engineEvents: AccessibilityEvent[],\n interactionEvents: AccessibilityEvent[]\n): AccessibilityEvent[] {\n const all = [...engineEvents, ...interactionEvents];\n all.sort((a, b) => a.timestamp - b.timestamp);\n return all;\n}\n\n/**\n * Get the source URL from a document, falling back to 'local'.\n */\nfunction getSourceUrl(doc: Document): string {\n try {\n const url = doc.URL;\n if (url && url !== 'about:blank' && url !== '') {\n return url;\n }\n } catch {\n // Ignore errors accessing URL\n }\n return 'local';\n}\n\n/**\n * Get the user agent string, defaulting to 'jsdom' for Node.js environments.\n */\nfunction getUserAgent(): string {\n try {\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return navigator.userAgent;\n }\n } catch {\n // Ignore errors\n }\n return 'jsdom';\n}\n\n/**\n * Simple promise-based delay.\n */\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Build an empty timeline for aborted captures.\n */\nfunction buildAbortedTimeline(\n componentName: string,\n storyName: string | undefined,\n sequence: InteractionSequence\n): AccessibilityTimeline {\n return {\n version: TIMELINE_FORMAT_VERSION,\n component: componentName,\n story: storyName || null,\n interactionSequence: sequence.description,\n duration: 0,\n events: [],\n warnings: [],\n metadata: {\n capturedAt: new Date().toISOString(),\n speakableVersion: SPEAKABLE_VERSION,\n sourceUrl: 'local',\n userAgent: getUserAgent(),\n },\n };\n}\n","/**\n * Built-in Interaction Patterns\n *\n * Provides pre-defined interaction sequences for common ARIA widget patterns.\n * Each pattern exercises standard keyboard interaction behavior as defined by\n * the WAI-ARIA Authoring Practices. Patterns use configurable selectors that\n * can be overridden to match component-specific markup.\n *\n * @module runtime/patterns\n */\n\nimport type { InteractionSequence, InteractionAction } from './types';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Optional map of CSS selectors to override defaults for built-in patterns.\n *\n * - `trigger` — element that opens/activates the widget\n * - `container` — wrapper/container element for the widget\n * - `content` — the content region within the widget\n * - `items` — individual items within the widget (options, tabs, etc.)\n * - `input` — text input element within the widget\n */\nexport interface PatternSelectorMap {\n trigger?: string;\n container?: string;\n content?: string;\n items?: string;\n input?: string;\n}\n\n/**\n * Names of built-in interaction patterns.\n */\nexport type BuiltinPatternName = 'modal-dialog' | 'combobox' | 'tabs' | 'accordion';\n\n// ---------------------------------------------------------------------------\n// Default Selectors\n// ---------------------------------------------------------------------------\n\nconst MODAL_DIALOG_DEFAULTS: Required<Pick<PatternSelectorMap, 'trigger' | 'container'>> = {\n trigger: 'button',\n container: '[role=\"dialog\"], dialog',\n};\n\nconst COMBOBOX_DEFAULTS: Required<Pick<PatternSelectorMap, 'input' | 'items'>> = {\n input: '[role=\"combobox\"], input[type=\"text\"]',\n items: '[role=\"option\"]',\n};\n\nconst TABS_DEFAULTS: Required<Pick<PatternSelectorMap, 'container' | 'items'>> = {\n container: '[role=\"tablist\"]',\n items: '[role=\"tab\"]',\n};\n\nconst ACCORDION_DEFAULTS: Required<Pick<PatternSelectorMap, 'trigger'>> = {\n trigger: 'button[aria-expanded]',\n};\n\n// ---------------------------------------------------------------------------\n// Pattern Builders\n// ---------------------------------------------------------------------------\n\n/**\n * Modal dialog pattern:\n * 1. Click trigger to open dialog\n * 2. Tab through dialog content (verify focus is in dialog)\n * 3. Tab through more content\n * 4. Press Escape to close\n * 5. Verify focus returns to trigger (implicit via focus observer)\n */\nfunction buildModalDialogPattern(selectors?: PatternSelectorMap): InteractionSequence {\n const trigger = selectors?.trigger ?? MODAL_DIALOG_DEFAULTS.trigger;\n\n const actions: InteractionAction[] = [\n { type: 'click', selector: trigger },\n { type: 'tab' },\n { type: 'tab' },\n { type: 'tab' },\n { type: 'escape' },\n ];\n\n return {\n description:\n 'Modal dialog: click trigger to open, tab through dialog content, press Escape to close, verify focus returns to trigger',\n actions,\n };\n}\n\n/**\n * Combobox pattern:\n * 1. Click/focus the combobox input\n * 2. Type to filter (simulated via key events)\n * 3. Arrow down through options\n * 4. Arrow down again\n * 5. Enter to select\n */\nfunction buildComboboxPattern(selectors?: PatternSelectorMap): InteractionSequence {\n const input = selectors?.input ?? COMBOBOX_DEFAULTS.input;\n\n const actions: InteractionAction[] = [\n { type: 'click', selector: input },\n { type: 'key', combo: 'a' },\n { type: 'arrowDown' },\n { type: 'arrowDown' },\n { type: 'enter' },\n ];\n\n return {\n description:\n 'Combobox: focus input, type to filter, navigate options with arrow keys, select with Enter',\n actions,\n };\n}\n\n/**\n * Tabs pattern:\n * 1. Click/focus the tablist container\n * 2. Arrow right to next tab\n * 3. Arrow right to next tab\n * 4. Enter to activate\n * 5. Arrow left to previous tab\n * 6. Space to activate\n */\nfunction buildTabsPattern(selectors?: PatternSelectorMap): InteractionSequence {\n const container = selectors?.container ?? TABS_DEFAULTS.container;\n\n const actions: InteractionAction[] = [\n { type: 'click', selector: container },\n { type: 'arrowRight' },\n { type: 'arrowRight' },\n { type: 'enter' },\n { type: 'arrowLeft' },\n { type: 'space' },\n ];\n\n return {\n description:\n 'Tabs: focus tablist, navigate between tabs with arrow keys, activate with Enter/Space',\n actions,\n };\n}\n\n/**\n * Accordion pattern:\n * 1. Click/focus the first accordion header\n * 2. Enter to toggle expanded/collapsed\n * 3. Arrow down to next header\n * 4. Space to toggle\n * 5. Arrow down to next header\n * 6. Enter to toggle\n */\nfunction buildAccordionPattern(selectors?: PatternSelectorMap): InteractionSequence {\n const trigger = selectors?.trigger ?? ACCORDION_DEFAULTS.trigger;\n\n const actions: InteractionAction[] = [\n { type: 'click', selector: trigger },\n { type: 'enter' },\n { type: 'arrowDown' },\n { type: 'space' },\n { type: 'arrowDown' },\n { type: 'enter' },\n ];\n\n return {\n description:\n 'Accordion: focus header, toggle with Enter/Space, navigate between headers with arrow keys',\n actions,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Get a built-in interaction pattern by name.\n *\n * Each pattern returns an InteractionSequence with a descriptive name and the\n * appropriate actions for testing common ARIA widget patterns. Optional selectors\n * can override the defaults used to locate trigger, container, and content elements.\n *\n * Default selectors:\n * - modal-dialog: trigger = 'button', container = '[role=\"dialog\"], dialog'\n * - combobox: input = '[role=\"combobox\"], input[type=\"text\"]', items = '[role=\"option\"]'\n * - tabs: container = '[role=\"tablist\"]', items = '[role=\"tab\"]'\n * - accordion: trigger = 'button[aria-expanded]'\n *\n * @param name - The built-in pattern name\n * @param selectors - Optional CSS selectors to override defaults\n * @returns An InteractionSequence representing the pattern\n */\nexport function getBuiltinPattern(\n name: BuiltinPatternName,\n selectors?: PatternSelectorMap\n): InteractionSequence {\n switch (name) {\n case 'modal-dialog':\n return buildModalDialogPattern(selectors);\n case 'combobox':\n return buildComboboxPattern(selectors);\n case 'tabs':\n return buildTabsPattern(selectors);\n case 'accordion':\n return buildAccordionPattern(selectors);\n }\n}\n","/**\n * Deterministic serialization and deserialization for Runtime Accessibility\n * Timeline types.\n *\n * All serializers produce JSON with recursively sorted keys and 2-space\n * indentation, guaranteeing:\n * - Byte-identical output for equivalent inputs (determinism)\n * - Round-trip integrity (serialize → deserialize → serialize = identical)\n * - Stable version-control diffs\n */\n\nimport type {\n AccessibilityEvent,\n AccessibilityTimeline,\n EventPayload,\n EventTarget,\n EventType,\n InteractionAction,\n InteractionSequence,\n TimelineMetadata,\n} from './types.js';\n\n// ---------------------------------------------------------------------------\n// Validation constants\n// ---------------------------------------------------------------------------\n\nconst VALID_EVENT_TYPES: ReadonlySet<string> = new Set<EventType>([\n 'FOCUS_CHANGED',\n 'ANNOUNCEMENT',\n 'DOM_MUTATION',\n 'ROLE_CHANGED',\n 'ACCESSIBLE_NAME_CHANGED',\n 'STATE_CHANGED',\n 'KEYBOARD_ACTION',\n 'DIALOG_OPENED',\n 'DIALOG_CLOSED',\n 'WARNING',\n 'REGRESSION',\n]);\n\nconst VALID_PAYLOAD_KINDS: ReadonlySet<string> = new Set([\n 'focus_changed',\n 'announcement',\n 'role_changed',\n 'accessible_name_changed',\n 'state_changed',\n 'dialog_opened',\n 'dialog_closed',\n 'keyboard_action',\n 'warning',\n]);\n\nconst VALID_ACTION_TYPES: ReadonlySet<string> = new Set([\n 'click',\n 'tab',\n 'shiftTab',\n 'escape',\n 'enter',\n 'space',\n 'arrowUp',\n 'arrowDown',\n 'arrowLeft',\n 'arrowRight',\n 'key',\n 'wait',\n]);\n\n// ---------------------------------------------------------------------------\n// Recursive key sorting\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively sorts all object keys in a value. Arrays are traversed but\n * their element order is preserved. Primitives pass through unchanged.\n */\nfunction sortKeysDeep<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map(sortKeysDeep) as unknown as T;\n }\n\n if (typeof value === 'object') {\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(value as Record<string, unknown>).sort();\n for (const key of keys) {\n sorted[key] = sortKeysDeep((value as Record<string, unknown>)[key]);\n }\n return sorted as T;\n }\n\n return value;\n}\n\n// ---------------------------------------------------------------------------\n// Event Serialization\n// ---------------------------------------------------------------------------\n\n/**\n * Serializes an AccessibilityEvent to deterministic JSON with sorted keys\n * and 2-space indentation.\n *\n * @param event - The accessibility event to serialize\n * @returns Deterministic JSON string\n */\nexport function serializeEvent(event: AccessibilityEvent): string {\n const sorted = sortKeysDeep(event);\n return JSON.stringify(sorted, null, 2);\n}\n\n/**\n * Deserializes a JSON string into a validated AccessibilityEvent.\n *\n * @param json - JSON string to parse\n * @returns Validated AccessibilityEvent\n * @throws Error if the JSON is invalid or does not conform to the event schema\n */\nexport function deserializeEvent(json: string): AccessibilityEvent {\n const parsed = JSON.parse(json);\n validateEvent(parsed);\n return parsed as AccessibilityEvent;\n}\n\n// ---------------------------------------------------------------------------\n// Timeline Serialization\n// ---------------------------------------------------------------------------\n\n/**\n * Serializes an AccessibilityTimeline to deterministic JSON with sorted keys\n * and 2-space indentation.\n *\n * @param timeline - The accessibility timeline to serialize\n * @returns Deterministic JSON string\n */\nexport function serializeTimeline(timeline: AccessibilityTimeline): string {\n const sorted = sortKeysDeep(timeline);\n return JSON.stringify(sorted, null, 2);\n}\n\n/**\n * Deserializes a JSON string into a validated AccessibilityTimeline.\n *\n * @param json - JSON string to parse\n * @returns Validated AccessibilityTimeline\n * @throws Error if the JSON is invalid or does not conform to the timeline schema\n */\nexport function deserializeTimeline(json: string): AccessibilityTimeline {\n const parsed = JSON.parse(json);\n validateTimeline(parsed);\n return parsed as AccessibilityTimeline;\n}\n\n// ---------------------------------------------------------------------------\n// InteractionSequence Serialization\n// ---------------------------------------------------------------------------\n\n/**\n * Serializes an InteractionSequence to deterministic JSON with sorted keys\n * and 2-space indentation.\n *\n * @param seq - The interaction sequence to serialize\n * @returns Deterministic JSON string\n */\nexport function serializeInteractionSequence(seq: InteractionSequence): string {\n const sorted = sortKeysDeep(seq);\n return JSON.stringify(sorted, null, 2);\n}\n\n/**\n * Deserializes a JSON string into a validated InteractionSequence.\n *\n * @param json - JSON string to parse\n * @returns Validated InteractionSequence\n * @throws Error if the JSON is invalid or does not conform to the interaction schema\n */\nexport function deserializeInteractionSequence(json: string): InteractionSequence {\n const parsed = JSON.parse(json);\n validateInteractionSequence(parsed);\n return parsed as InteractionSequence;\n}\n\n// ---------------------------------------------------------------------------\n// Deep Equality\n// ---------------------------------------------------------------------------\n\n/**\n * Checks whether two AccessibilityTimelines are deeply equal by comparing\n * their deterministic serializations. Because serialization sorts keys\n * recursively, structurally equivalent timelines produce identical strings.\n *\n * @param a - First timeline\n * @param b - Second timeline\n * @returns true if timelines are equivalent\n */\nexport function timelinesEqual(\n a: AccessibilityTimeline,\n b: AccessibilityTimeline,\n): boolean {\n return serializeTimeline(a) === serializeTimeline(b);\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\nfunction validateEvent(obj: unknown): asserts obj is AccessibilityEvent {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('Event must be a non-null object');\n }\n\n const event = obj as Record<string, unknown>;\n\n // type\n if (typeof event.type !== 'string' || !VALID_EVENT_TYPES.has(event.type)) {\n throw new Error(\n `Event \"type\" must be one of: ${[...VALID_EVENT_TYPES].join(', ')}. Got: ${String(event.type)}`,\n );\n }\n\n // timestamp\n if (typeof event.timestamp !== 'number' || !Number.isFinite(event.timestamp)) {\n throw new Error('Event \"timestamp\" must be a finite number');\n }\n\n // target\n validateEventTarget(event.target, 'Event \"target\"');\n\n // payload\n validatePayload(event.payload);\n}\n\nfunction validateEventTarget(obj: unknown, label: string): asserts obj is EventTarget {\n if (obj === null || typeof obj !== 'object') {\n throw new Error(`${label} must be a non-null object`);\n }\n\n const target = obj as Record<string, unknown>;\n\n if (typeof target.role !== 'string') {\n throw new Error(`${label}.role must be a string`);\n }\n if (typeof target.accessibleName !== 'string') {\n throw new Error(`${label}.accessibleName must be a string`);\n }\n if (typeof target.selector !== 'string') {\n throw new Error(`${label}.selector must be a string`);\n }\n}\n\nfunction validatePayload(obj: unknown): asserts obj is EventPayload {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('Event \"payload\" must be a non-null object');\n }\n\n const payload = obj as Record<string, unknown>;\n\n if (typeof payload.kind !== 'string' || !VALID_PAYLOAD_KINDS.has(payload.kind)) {\n throw new Error(\n `Payload \"kind\" must be one of: ${[...VALID_PAYLOAD_KINDS].join(', ')}. Got: ${String(payload.kind)}`,\n );\n }\n\n // Type-specific validation\n switch (payload.kind) {\n case 'focus_changed':\n if (payload.previousTarget !== null) {\n validateEventTarget(payload.previousTarget, 'FocusChangedPayload.previousTarget');\n }\n break;\n\n case 'announcement':\n if (payload.politeness !== 'polite' && payload.politeness !== 'assertive') {\n throw new Error('AnnouncementPayload.politeness must be \"polite\" or \"assertive\"');\n }\n if (typeof payload.text !== 'string') {\n throw new Error('AnnouncementPayload.text must be a string');\n }\n break;\n\n case 'role_changed':\n if (typeof payload.previousRole !== 'string') {\n throw new Error('RoleChangedPayload.previousRole must be a string');\n }\n if (typeof payload.newRole !== 'string') {\n throw new Error('RoleChangedPayload.newRole must be a string');\n }\n break;\n\n case 'accessible_name_changed':\n if (typeof payload.previousName !== 'string') {\n throw new Error('AccessibleNameChangedPayload.previousName must be a string');\n }\n if (typeof payload.newName !== 'string') {\n throw new Error('AccessibleNameChangedPayload.newName must be a string');\n }\n break;\n\n case 'state_changed':\n if (typeof payload.attribute !== 'string') {\n throw new Error('StateChangedPayload.attribute must be a string');\n }\n validateStateValue(payload.previousValue, 'StateChangedPayload.previousValue');\n validateStateValue(payload.newValue, 'StateChangedPayload.newValue');\n break;\n\n case 'dialog_opened':\n if (typeof payload.dialogName !== 'string') {\n throw new Error('DialogOpenedPayload.dialogName must be a string');\n }\n if (typeof payload.isModal !== 'boolean') {\n throw new Error('DialogOpenedPayload.isModal must be a boolean');\n }\n break;\n\n case 'dialog_closed':\n if (typeof payload.dialogName !== 'string') {\n throw new Error('DialogClosedPayload.dialogName must be a string');\n }\n break;\n\n case 'keyboard_action':\n if (typeof payload.key !== 'string') {\n throw new Error('KeyboardActionPayload.key must be a string');\n }\n if (!Array.isArray(payload.modifiers)) {\n throw new Error('KeyboardActionPayload.modifiers must be an array');\n }\n for (const mod of payload.modifiers) {\n if (typeof mod !== 'string') {\n throw new Error('KeyboardActionPayload.modifiers must contain only strings');\n }\n }\n break;\n\n case 'warning':\n if (typeof payload.message !== 'string') {\n throw new Error('WarningPayload.message must be a string');\n }\n if (payload.relatedEvent !== undefined && payload.relatedEvent !== null) {\n validateEvent(payload.relatedEvent);\n }\n break;\n }\n}\n\nfunction validateStateValue(value: unknown, label: string): void {\n if (value !== null && typeof value !== 'string' && typeof value !== 'boolean') {\n throw new Error(`${label} must be a string, boolean, or null`);\n }\n}\n\nfunction validateTimeline(obj: unknown): asserts obj is AccessibilityTimeline {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('Timeline must be a non-null object');\n }\n\n const timeline = obj as Record<string, unknown>;\n\n // version\n if (typeof timeline.version !== 'string') {\n throw new Error('Timeline \"version\" must be a string');\n }\n\n // component\n if (typeof timeline.component !== 'string') {\n throw new Error('Timeline \"component\" must be a string');\n }\n\n // story (string | null)\n if (timeline.story !== null && typeof timeline.story !== 'string') {\n throw new Error('Timeline \"story\" must be a string or null');\n }\n\n // interactionSequence\n if (typeof timeline.interactionSequence !== 'string') {\n throw new Error('Timeline \"interactionSequence\" must be a string');\n }\n\n // duration\n if (typeof timeline.duration !== 'number' || !Number.isFinite(timeline.duration)) {\n throw new Error('Timeline \"duration\" must be a finite number');\n }\n\n // events\n if (!Array.isArray(timeline.events)) {\n throw new Error('Timeline \"events\" must be an array');\n }\n for (let i = 0; i < timeline.events.length; i++) {\n try {\n validateEvent(timeline.events[i]);\n } catch (err) {\n throw new Error(\n `Timeline events[${i}]: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // warnings\n if (!Array.isArray(timeline.warnings)) {\n throw new Error('Timeline \"warnings\" must be an array');\n }\n for (let i = 0; i < timeline.warnings.length; i++) {\n try {\n validateEvent(timeline.warnings[i]);\n } catch (err) {\n throw new Error(\n `Timeline warnings[${i}]: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // metadata\n validateTimelineMetadata(timeline.metadata);\n}\n\nfunction validateTimelineMetadata(obj: unknown): asserts obj is TimelineMetadata {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('Timeline \"metadata\" must be a non-null object');\n }\n\n const meta = obj as Record<string, unknown>;\n\n if (typeof meta.capturedAt !== 'string') {\n throw new Error('Timeline metadata.capturedAt must be a string');\n }\n if (typeof meta.speakableVersion !== 'string') {\n throw new Error('Timeline metadata.speakableVersion must be a string');\n }\n if (typeof meta.sourceUrl !== 'string') {\n throw new Error('Timeline metadata.sourceUrl must be a string');\n }\n if (typeof meta.userAgent !== 'string') {\n throw new Error('Timeline metadata.userAgent must be a string');\n }\n}\n\nfunction validateInteractionSequence(obj: unknown): asserts obj is InteractionSequence {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('InteractionSequence must be a non-null object');\n }\n\n const seq = obj as Record<string, unknown>;\n\n if (typeof seq.description !== 'string') {\n throw new Error('InteractionSequence \"description\" must be a string');\n }\n\n if (!Array.isArray(seq.actions)) {\n throw new Error('InteractionSequence \"actions\" must be an array');\n }\n\n for (let i = 0; i < seq.actions.length; i++) {\n validateAction(seq.actions[i], i);\n }\n}\n\nfunction validateAction(obj: unknown, index: number): asserts obj is InteractionAction {\n if (obj === null || typeof obj !== 'object') {\n throw new Error(`InteractionSequence actions[${index}] must be a non-null object`);\n }\n\n const action = obj as Record<string, unknown>;\n\n if (typeof action.type !== 'string' || !VALID_ACTION_TYPES.has(action.type)) {\n throw new Error(\n `InteractionSequence actions[${index}].type must be one of: ${[...VALID_ACTION_TYPES].join(', ')}. Got: ${String(action.type)}`,\n );\n }\n\n switch (action.type) {\n case 'click':\n if (typeof action.selector !== 'string') {\n throw new Error(\n `InteractionSequence actions[${index}].selector must be a string for click actions`,\n );\n }\n break;\n\n case 'key':\n if (typeof action.combo !== 'string') {\n throw new Error(\n `InteractionSequence actions[${index}].combo must be a string for key actions`,\n );\n }\n break;\n\n case 'wait':\n if (typeof action.ms !== 'number' || !Number.isFinite(action.ms)) {\n throw new Error(\n `InteractionSequence actions[${index}].ms must be a finite number for wait actions`,\n );\n }\n break;\n }\n}\n","/**\n * Behavior Diff Engine\n *\n * Compares two Accessibility Timelines and produces a BehaviorDiffReport\n * describing added, removed, and modified events. Events are matched by\n * type + target selector. Timestamp differences alone do not count as\n * modifications.\n */\n\nimport type { AccessibilityEvent, AccessibilityTimeline } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Public Interfaces\n// ---------------------------------------------------------------------------\n\n/**\n * A single entry in the diff report representing one difference between\n * baseline and current timelines.\n */\nexport interface DiffEntry {\n /** The event from the current timeline (for added/modified) or baseline (for removed) */\n event: AccessibilityEvent;\n /** The corresponding event from the other timeline (for modified entries) */\n previousEvent?: AccessibilityEvent;\n /** Human-readable description of the difference */\n message: string;\n}\n\n/**\n * Structured summary of differences between two Accessibility Timelines.\n */\nexport interface BehaviorDiffReport {\n baseline: { totalEvents: number };\n current: { totalEvents: number };\n /** Events present in current but not in baseline */\n added: DiffEntry[];\n /** Events present in baseline but not in current */\n removed: DiffEntry[];\n /** Events present in both but with different payloads */\n modified: DiffEntry[];\n /** Aggregate counts (must equal array lengths exactly) */\n summary: {\n totalBaseline: number;\n totalCurrent: number;\n added: number;\n removed: number;\n modified: number;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internal Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a matching key for an event based on type and target selector.\n * This is the primary key used to correlate events across timelines.\n */\nfunction matchingKey(event: AccessibilityEvent): string {\n return `${event.type}::${event.target.selector}`;\n}\n\n/**\n * Compare two event payloads for equality, ignoring the timestamp field.\n * Returns true if payloads are structurally identical.\n */\nfunction payloadsEqual(a: AccessibilityEvent, b: AccessibilityEvent): boolean {\n // Compare everything except timestamp\n // We compare: type, target, and payload\n if (a.type !== b.type) return false;\n if (!targetsEqual(a.target, b.target)) return false;\n return deepEqual(a.payload, b.payload);\n}\n\n/**\n * Compare two EventTarget objects for equality.\n */\nfunction targetsEqual(\n a: AccessibilityEvent['target'],\n b: AccessibilityEvent['target']\n): boolean {\n return (\n a.role === b.role &&\n a.accessibleName === b.accessibleName &&\n a.selector === b.selector\n );\n}\n\n/**\n * Deep equality check for payload objects.\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n if (typeof a !== 'object') return a === b;\n\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n\n const aKeys = Object.keys(aObj).sort();\n const bKeys = Object.keys(bObj).sort();\n\n if (aKeys.length !== bKeys.length) return false;\n\n for (let i = 0; i < aKeys.length; i++) {\n if (aKeys[i] !== bKeys[i]) return false;\n if (!deepEqual(aObj[aKeys[i]], bObj[bKeys[i]])) return false;\n }\n\n return true;\n}\n\n/**\n * Build a human-readable message describing a modification.\n */\nfunction buildModifiedMessage(\n baseline: AccessibilityEvent,\n current: AccessibilityEvent\n): string {\n const type = current.type;\n const selector = current.target.selector;\n\n // Check if target properties changed\n if (baseline.target.accessibleName !== current.target.accessibleName) {\n return (\n `${type} on \"${selector}\": accessible name changed from ` +\n `\"${baseline.target.accessibleName}\" to \"${current.target.accessibleName}\"`\n );\n }\n\n if (baseline.target.role !== current.target.role) {\n return (\n `${type} on \"${selector}\": role changed from ` +\n `\"${baseline.target.role}\" to \"${current.target.role}\"`\n );\n }\n\n // Generic payload difference message\n return `${type} on \"${selector}\": payload values differ`;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Compare two Accessibility Timelines and produce a structured diff report.\n *\n * Algorithm:\n * 1. Create matching keys for events: type + target selector\n * 2. Walk baseline events and find matching current events\n * 3. If matched: compare payloads (ignoring timestamp). Different = modified.\n * 4. If no match in current: classify as removed\n * 5. Unmatched current events: classify as added\n * 6. Timestamp-only differences do NOT count as modifications\n */\nexport function diffTimelines(\n baseline: AccessibilityTimeline,\n current: AccessibilityTimeline\n): BehaviorDiffReport {\n const added: DiffEntry[] = [];\n const removed: DiffEntry[] = [];\n const modified: DiffEntry[] = [];\n\n // Group current events by matching key, maintaining order within each key.\n // We use arrays to handle multiple events with the same key (e.g., multiple\n // focus changes on the same element).\n const currentByKey = new Map<string, AccessibilityEvent[]>();\n for (const event of current.events) {\n const key = matchingKey(event);\n const existing = currentByKey.get(key);\n if (existing) {\n existing.push(event);\n } else {\n currentByKey.set(key, [event]);\n }\n }\n\n // Track which current events have been matched to a baseline event\n const matchedCurrentIndices = new Set<string>();\n\n // Walk through baseline events\n for (const baselineEvent of baseline.events) {\n const key = matchingKey(baselineEvent);\n const candidates = currentByKey.get(key);\n\n if (!candidates || candidates.length === 0) {\n // No matching event in current timeline\n removed.push({\n event: baselineEvent,\n message: `${baselineEvent.type} on \"${baselineEvent.target.selector}\" was removed`,\n });\n continue;\n }\n\n // Find the first unmatched candidate with the same key\n let matched = false;\n for (let i = 0; i < candidates.length; i++) {\n const candidateId = `${key}::${i}`;\n if (matchedCurrentIndices.has(candidateId)) continue;\n\n const currentEvent = candidates[i];\n matchedCurrentIndices.add(candidateId);\n\n // Compare ignoring timestamp\n if (!payloadsEqual(baselineEvent, currentEvent)) {\n modified.push({\n event: currentEvent,\n previousEvent: baselineEvent,\n message: buildModifiedMessage(baselineEvent, currentEvent),\n });\n }\n // If payloads are equal (only timestamp differs), it is not a modification\n\n matched = true;\n break;\n }\n\n if (!matched) {\n // All candidates with this key were already consumed\n removed.push({\n event: baselineEvent,\n message: `${baselineEvent.type} on \"${baselineEvent.target.selector}\" was removed`,\n });\n }\n }\n\n // Any unmatched current events are additions\n for (const [key, candidates] of currentByKey.entries()) {\n for (let i = 0; i < candidates.length; i++) {\n const candidateId = `${key}::${i}`;\n if (!matchedCurrentIndices.has(candidateId)) {\n const event = candidates[i];\n added.push({\n event,\n message: `${event.type} on \"${event.target.selector}\" was added`,\n });\n }\n }\n }\n\n return {\n baseline: { totalEvents: baseline.events.length },\n current: { totalEvents: current.events.length },\n added,\n removed,\n modified,\n summary: {\n totalBaseline: baseline.events.length,\n totalCurrent: current.events.length,\n added: added.length,\n removed: removed.length,\n modified: modified.length,\n },\n };\n}\n","import type { AccessibilityEvent } from './types.js';\nimport type { BehaviorDiffReport, DiffEntry } from './diff-engine.js';\n\nexport type SeverityLevel = 'critical' | 'high' | 'medium' | 'low';\n\nexport interface ClassifiedDiffEntry {\n event: AccessibilityEvent;\n previousEvent?: AccessibilityEvent;\n message: string;\n severity: SeverityLevel;\n}\n\nexport interface ClassifiedDiffReport {\n entries: ClassifiedDiffEntry[];\n highestSeverity: SeverityLevel | null;\n criticalCount: number;\n highCount: number;\n mediumCount: number;\n lowCount: number;\n}\n\nexport function classifyDiff(report: BehaviorDiffReport): ClassifiedDiffReport {\n const entries: ClassifiedDiffEntry[] = [];\n\n // Removed events\n for (const entry of report.removed) {\n const severity = classifyRemoved(entry);\n entries.push({ ...entry, severity });\n }\n\n // Added events\n for (const entry of report.added) {\n const severity = classifyAdded(entry);\n entries.push({ ...entry, severity });\n }\n\n // Modified events\n for (const entry of report.modified) {\n const severity = classifyModified(entry);\n entries.push({ ...entry, severity });\n }\n\n const criticalCount = entries.filter(e => e.severity === 'critical').length;\n const highCount = entries.filter(e => e.severity === 'high').length;\n const mediumCount = entries.filter(e => e.severity === 'medium').length;\n const lowCount = entries.filter(e => e.severity === 'low').length;\n\n let highestSeverity: SeverityLevel | null = null;\n if (criticalCount > 0) highestSeverity = 'critical';\n else if (highCount > 0) highestSeverity = 'high';\n else if (mediumCount > 0) highestSeverity = 'medium';\n else if (lowCount > 0) highestSeverity = 'low';\n\n return { entries, highestSeverity, criticalCount, highCount, mediumCount, lowCount };\n}\n\nfunction classifyRemoved(entry: DiffEntry): SeverityLevel {\n switch (entry.event.type) {\n case 'FOCUS_CHANGED': return 'critical';\n case 'ANNOUNCEMENT': return 'critical';\n case 'DIALOG_OPENED': return 'high';\n case 'DIALOG_CLOSED': return 'high';\n case 'STATE_CHANGED': return 'high';\n case 'KEYBOARD_ACTION': return 'medium';\n default: return 'medium';\n }\n}\n\nfunction classifyAdded(entry: DiffEntry): SeverityLevel {\n switch (entry.event.type) {\n case 'WARNING': return 'high';\n case 'REGRESSION': return 'critical';\n case 'ANNOUNCEMENT': return 'medium';\n case 'FOCUS_CHANGED': return 'medium';\n default: return 'low';\n }\n}\n\nfunction classifyModified(entry: DiffEntry): SeverityLevel {\n switch (entry.event.type) {\n case 'FOCUS_CHANGED': return 'high';\n case 'STATE_CHANGED': return 'high';\n case 'ACCESSIBLE_NAME_CHANGED': return 'medium';\n case 'ANNOUNCEMENT': return 'medium';\n default: return 'medium';\n }\n}\n","import { readFile, writeFile, mkdir, access } from 'fs/promises';\nimport { join, dirname } from 'path';\nimport type { AccessibilityTimeline } from './types.js';\n\nconst SPEAKABLE_VERSION = '1.3.0';\n\nexport interface BaselineFile {\n baseline: {\n createdAt: string;\n speakableVersion: string;\n storybookUrl?: string;\n interactionSequence: string;\n };\n timeline: AccessibilityTimeline;\n}\n\nexport interface BaselineStorage {\n save(componentName: string, storyName: string, timeline: AccessibilityTimeline, meta?: { storybookUrl?: string }): Promise<void>;\n load(componentName: string, storyName: string): Promise<BaselineFile | null>;\n exists(componentName: string, storyName: string): Promise<boolean>;\n getBaselinePath(componentName: string, storyName: string): string;\n}\n\nexport function createBaselineStorage(baseDir: string): BaselineStorage {\n function sanitize(name: string): string {\n return name.toLowerCase().replace(/[/\\\\]/g, '-').replace(/[^a-z0-9._-]/g, '-');\n }\n\n function getPath(componentName: string, storyName: string): string {\n return join(baseDir, sanitize(componentName), `${sanitize(storyName)}.timeline.json`);\n }\n\n return {\n async save(componentName, storyName, timeline, meta) {\n const filePath = getPath(componentName, storyName);\n const dir = dirname(filePath);\n\n try {\n await mkdir(dir, { recursive: true });\n } catch (err) {\n throw new Error(`Cannot create baseline directory \"${dir}\": ${(err as Error).message}`);\n }\n\n const baselineFile: BaselineFile = {\n baseline: {\n createdAt: new Date().toISOString(),\n speakableVersion: SPEAKABLE_VERSION,\n storybookUrl: meta?.storybookUrl,\n interactionSequence: timeline.interactionSequence,\n },\n timeline,\n };\n\n const json = JSON.stringify(baselineFile, null, 2);\n\n try {\n await writeFile(filePath, json, 'utf-8');\n } catch (err) {\n throw new Error(`Cannot write baseline file \"${filePath}\": ${(err as Error).message}`);\n }\n },\n\n async load(componentName, storyName) {\n const filePath = getPath(componentName, storyName);\n try {\n const content = await readFile(filePath, 'utf-8');\n const parsed = JSON.parse(content) as BaselineFile;\n return parsed;\n } catch {\n return null;\n }\n },\n\n async exists(componentName, storyName) {\n const filePath = getPath(componentName, storyName);\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n },\n\n getBaselinePath(componentName, storyName) {\n return getPath(componentName, storyName);\n },\n };\n}\n","/**\n * Verbosity Analyzer\n *\n * Detects redundant and duplicate announcement patterns in accessibility\n * event timelines. While the heuristic analyzer catches \"too many announcements\n * in a time window,\" this module performs deeper semantic analysis to identify\n * WHY announcements are being duplicated, and provides specific remediation\n * guidance.\n *\n * Detected patterns:\n *\n * 1. **Redundant state + live region** — When aria-selected/aria-checked changes\n * on an element AND a live region announces the same state change, screen\n * readers (especially VoiceOver) will read both.\n *\n * 2. **ActiveDescendant + state change on same element** — When\n * aria-activedescendant moves to an element AND that element's state changes\n * in the same interaction frame, VoiceOver reads the element twice.\n *\n * 3. **Name change + live region echo** — When an element's accessible name\n * changes and a live region repeats that same content.\n *\n * 4. **Focus + activedescendant conflict** — When real DOM focus moves AND\n * aria-activedescendant changes in the same frame, causing double-read.\n *\n * 5. **Multiple state changes on one element** — When several ARIA attributes\n * change simultaneously on a single element, each triggering a separate read.\n *\n * @module runtime/verbosity-analyzer\n */\n\nimport type { AccessibilityEvent, StateChangedPayload, AnnouncementPayload } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Severity of a verbosity issue.\n * - \"high\": Users will definitely hear duplicate content (e.g., VoiceOver triple-read)\n * - \"medium\": Users will likely hear repeated info depending on screen reader settings\n * - \"low\": Potential redundancy that may only affect certain screen readers\n */\nexport type VerbositySeverity = 'high' | 'medium' | 'low';\n\n/**\n * Category of the verbosity pattern detected.\n */\nexport type VerbosityPattern =\n | 'redundant-state-and-live-region'\n | 'activedescendant-plus-state-change'\n | 'name-change-plus-live-region'\n | 'focus-plus-activedescendant'\n | 'multiple-state-changes-same-element'\n | 'rapid-identical-announcements';\n\n/**\n * A single verbosity finding with context and remediation guidance.\n */\nexport interface VerbosityFinding {\n /** Pattern category */\n pattern: VerbosityPattern;\n /** Severity level */\n severity: VerbositySeverity;\n /** Human-readable description of the problem */\n description: string;\n /** Specific remediation steps */\n remediation: string[];\n /** Which screen readers are most affected */\n affectedReaders: string[];\n /** The events that triggered this finding */\n relatedEvents: AccessibilityEvent[];\n /** Timestamp window where the duplicate occurred */\n timeWindow: { start: number; end: number };\n /** CSS selector of the element involved */\n elementSelector: string;\n}\n\n/**\n * Complete verbosity analysis report for a timeline.\n */\nexport interface VerbosityReport {\n /** All findings sorted by severity (high first) */\n findings: VerbosityFinding[];\n /** Summary counts by severity */\n summary: {\n high: number;\n medium: number;\n low: number;\n total: number;\n };\n /** Overall verbosity score (0-100, lower is better) */\n score: number;\n}\n\n/**\n * Configuration for the verbosity analyzer.\n */\nexport interface VerbosityConfig {\n /** Time window (ms) to group related events into a single interaction frame (default: 150) */\n interactionFrameWindow: number;\n /** Minimum text similarity ratio to consider live region content redundant (default: 0.6) */\n textSimilarityThreshold: number;\n}\n\nconst DEFAULT_CONFIG: VerbosityConfig = {\n interactionFrameWindow: 150,\n textSimilarityThreshold: 0.6,\n};\n\n// ---------------------------------------------------------------------------\n// Text Similarity\n// ---------------------------------------------------------------------------\n\n/**\n * Computes a simple word-overlap similarity ratio between two strings.\n * Returns a value between 0 and 1.\n */\nfunction textSimilarity(a: string, b: string): number {\n if (!a || !b) return 0;\n const wordsA = new Set(a.toLowerCase().split(/\\s+/).filter(Boolean));\n const wordsB = new Set(b.toLowerCase().split(/\\s+/).filter(Boolean));\n if (wordsA.size === 0 || wordsB.size === 0) return 0;\n\n let overlap = 0;\n for (const word of wordsA) {\n if (wordsB.has(word)) overlap++;\n }\n\n const maxSize = Math.max(wordsA.size, wordsB.size);\n return overlap / maxSize;\n}\n\n// ---------------------------------------------------------------------------\n// Interaction Frame Grouping\n// ---------------------------------------------------------------------------\n\ninterface InteractionFrame {\n start: number;\n end: number;\n events: AccessibilityEvent[];\n}\n\n/**\n * Groups events into interaction frames based on temporal proximity.\n * Events within `windowMs` of each other are considered part of the\n * same user interaction.\n */\nfunction groupIntoFrames(events: AccessibilityEvent[], windowMs: number): InteractionFrame[] {\n if (events.length === 0) return [];\n\n const frames: InteractionFrame[] = [];\n let currentFrame: InteractionFrame = {\n start: events[0].timestamp,\n end: events[0].timestamp,\n events: [events[0]],\n };\n\n for (let i = 1; i < events.length; i++) {\n const event = events[i];\n if (event.timestamp - currentFrame.end <= windowMs) {\n currentFrame.events.push(event);\n currentFrame.end = event.timestamp;\n } else {\n frames.push(currentFrame);\n currentFrame = {\n start: event.timestamp,\n end: event.timestamp,\n events: [event],\n };\n }\n }\n\n frames.push(currentFrame);\n return frames;\n}\n\n// ---------------------------------------------------------------------------\n// Pattern Detection\n// ---------------------------------------------------------------------------\n\nfunction detectRedundantStateAndLiveRegion(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const stateChanges = frame.events.filter((e) => e.type === 'STATE_CHANGED');\n const announcements = frame.events.filter((e) => e.type === 'ANNOUNCEMENT');\n\n for (const stateEvent of stateChanges) {\n const payload = stateEvent.payload as StateChangedPayload;\n\n // Only relevant for state attributes that screen readers announce\n const announcedAttributes = [\n 'aria-selected', 'aria-checked', 'aria-pressed', 'aria-expanded',\n 'aria-disabled', 'aria-invalid', 'aria-current',\n ];\n if (!announcedAttributes.includes(payload.attribute)) continue;\n\n for (const announcement of announcements) {\n const annoPayload = announcement.payload as AnnouncementPayload;\n const annoText = annoPayload.text.toLowerCase();\n const elementName = stateEvent.target.accessibleName.toLowerCase();\n\n // Check if the live region text contains the element's name\n // (which indicates it's providing feedback about the same element\n // whose state just changed, meaning the SR will announce both)\n const nameInAnnouncement = elementName.length > 0 && annoText.includes(elementName);\n\n // Also check for state-related words that echo what the SR already announces\n const stateEchoWords = ['selected', 'deselected', 'checked', 'unchecked', 'expanded', 'collapsed', 'pressed'];\n const hasStateEcho = stateEchoWords.some((word) => annoText.includes(word));\n\n if (nameInAnnouncement && hasStateEcho) {\n findings.push({\n pattern: 'redundant-state-and-live-region',\n severity: 'high',\n description:\n `The ${payload.attribute} state change on \"${stateEvent.target.accessibleName}\" ` +\n `(${stateEvent.target.role}) is already announced by the screen reader, but a live ` +\n `region also announces similar content (\"${annoPayload.text}\"). ` +\n `This causes VoiceOver to read the information 2-3 times.`,\n remediation: [\n `Remove the live region announcement when ${payload.attribute} changes on the active element, ` +\n `since the screen reader already announces state transitions on the focused/active item.`,\n `If you need the live region for summary info (e.g., \"3 of 5 selected\"), ` +\n `debounce it with a 150ms+ delay and ensure the text does NOT repeat the option name.`,\n `Use a summary-only pattern in the live region: \"3 of 5 selected\" instead of ` +\n `\"JavaScript selected. 3 of 5 selected.\" The element name is already announced ` +\n `via the state change.`,\n `Consider removing the live region entirely and relying on aria-selected/aria-checked ` +\n `state changes for per-item feedback.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'VoiceOver (iOS)'],\n relatedEvents: [stateEvent, announcement],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: stateEvent.target.selector,\n });\n }\n }\n }\n\n return findings;\n}\n\nfunction detectActiveDescendantPlusStateChange(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n // Look for STATE_CHANGED events where attribute is aria-activedescendant\n const activedescendantChanges = frame.events.filter(\n (e) => e.type === 'STATE_CHANGED' &&\n (e.payload as StateChangedPayload).attribute === 'aria-activedescendant'\n );\n\n const otherStateChanges = frame.events.filter(\n (e) => e.type === 'STATE_CHANGED' &&\n (e.payload as StateChangedPayload).attribute !== 'aria-activedescendant'\n );\n\n for (const adChange of activedescendantChanges) {\n const adPayload = adChange.payload as StateChangedPayload;\n const newValue = String(adPayload.newValue);\n const previousValue = String(adPayload.previousValue ?? '');\n\n // If activedescendant is being re-set to the SAME value, that's always a bug.\n // If it's moving to a DIFFERENT element, we only flag it if a state change\n // occurs on that same target within the frame (which causes double-read on VoiceOver).\n const isSameElement = newValue === previousValue;\n\n for (const stateChange of otherStateChanges) {\n const statePayload = stateChange.payload as StateChangedPayload;\n\n // Check if the state change is on the element that activedescendant points to\n const targetMatchesAD = stateChange.target.selector.includes(newValue) ||\n stateChange.target.selector === adChange.target.selector;\n\n if (!targetMatchesAD) continue;\n\n if (isSameElement) {\n // Definite bug: re-setting activedescendant to same element AND changing its state\n findings.push({\n pattern: 'activedescendant-plus-state-change',\n severity: 'high',\n description:\n `aria-activedescendant was re-set to the same value (\"${newValue}\") ` +\n `AND ${statePayload.attribute} changed on that element within ${frame.end - frame.start}ms. ` +\n `VoiceOver reads the element once for the activedescendant update, then again for the state change.`,\n remediation: [\n `When toggling selection on the already-active option, do NOT re-set aria-activedescendant ` +\n `to the same value. Only update it when the user navigates to a different option.`,\n `Batch DOM attribute changes: set aria-selected BEFORE updating aria-activedescendant, ` +\n `or skip the activedescendant update entirely when the active item hasn't changed.`,\n `For click interactions on options, avoid calling both setActiveDescendant() and ` +\n `toggleSelection() if the clicked item is already the active descendant.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'VoiceOver (iOS)', 'Narrator'],\n relatedEvents: [adChange, stateChange],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: stateChange.target.selector,\n });\n } else {\n // Moving to a different element + changing state is borderline.\n // Only flag as low severity since VoiceOver announcing the navigation\n // AND the state is sometimes the desired UX (click = navigate + select).\n findings.push({\n pattern: 'activedescendant-plus-state-change',\n severity: 'low',\n description:\n `aria-activedescendant moved to \"${stateChange.target.accessibleName}\" ` +\n `AND ${statePayload.attribute} changed on that element within ${frame.end - frame.start}ms. ` +\n `VoiceOver may announce the option name twice (once for navigation, once for state).`,\n remediation: [\n `If this is a click-to-select interaction, consider separating the activedescendant ` +\n `update and the state change by a microtask (Promise.resolve()) so VoiceOver ` +\n `processes them as separate assertions.`,\n `Alternatively, accept this as expected behavior for click interactions where ` +\n `navigation and selection happen simultaneously.`,\n ],\n affectedReaders: ['VoiceOver (macOS)'],\n relatedEvents: [adChange, stateChange],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: stateChange.target.selector,\n });\n }\n }\n }\n\n return findings;\n}\n\nfunction detectNameChangePlusLiveRegion(\n frame: InteractionFrame,\n config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const nameChanges = frame.events.filter((e) => e.type === 'ACCESSIBLE_NAME_CHANGED');\n const announcements = frame.events.filter((e) => e.type === 'ANNOUNCEMENT');\n\n for (const nameEvent of nameChanges) {\n for (const announcement of announcements) {\n const annoPayload = announcement.payload as AnnouncementPayload;\n const similarity = textSimilarity(nameEvent.target.accessibleName, annoPayload.text);\n\n if (similarity >= config.textSimilarityThreshold) {\n findings.push({\n pattern: 'name-change-plus-live-region',\n severity: 'medium',\n description:\n `The accessible name of \"${nameEvent.target.accessibleName}\" (${nameEvent.target.role}) ` +\n `changed AND a live region announced similar content (\"${annoPayload.text}\"). ` +\n `Screen readers may announce both the name change and the live region.`,\n remediation: [\n `Choose one announcement channel: either update the element's accessible name ` +\n `(which the screen reader reads if the element is focused) OR use a live region, not both.`,\n `If the element is focused, prefer the name change. If it's not focused, prefer the live region.`,\n `Add a 200ms+ debounce to the live region update to let the name change announce first.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'NVDA', 'JAWS'],\n relatedEvents: [nameEvent, announcement],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: nameEvent.target.selector,\n });\n }\n }\n }\n\n return findings;\n}\n\nfunction detectFocusPlusActiveDescendant(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const focusEvents = frame.events.filter((e) => e.type === 'FOCUS_CHANGED');\n const adChanges = frame.events.filter(\n (e) => e.type === 'STATE_CHANGED' &&\n (e.payload as StateChangedPayload).attribute === 'aria-activedescendant'\n );\n\n if (focusEvents.length > 0 && adChanges.length > 0) {\n findings.push({\n pattern: 'focus-plus-activedescendant',\n severity: 'medium',\n description:\n `Both real DOM focus moved AND aria-activedescendant changed within ${frame.end - frame.start}ms. ` +\n `Screen readers may announce the focused element AND then re-announce via activedescendant, ` +\n `causing a double-read.`,\n remediation: [\n `Choose one focus management strategy: either move real DOM focus to options (roving tabindex) ` +\n `OR use aria-activedescendant on the container. Do not mix both.`,\n `If using aria-activedescendant, keep DOM focus on the container (listbox/combobox) ` +\n `and only change the activedescendant attribute.`,\n `If using roving tabindex, set tabindex=\"0\" on the active item and tabindex=\"-1\" on others, ` +\n `and move focus directly via element.focus().`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'NVDA', 'JAWS', 'Narrator'],\n relatedEvents: [...focusEvents, ...adChanges],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: focusEvents[0].target.selector,\n });\n }\n\n return findings;\n}\n\nfunction detectMultipleStateChangesSameElement(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const stateChanges = frame.events.filter((e) => e.type === 'STATE_CHANGED');\n\n // Group by target selector\n const bySelector = new Map<string, AccessibilityEvent[]>();\n for (const event of stateChanges) {\n const existing = bySelector.get(event.target.selector) || [];\n existing.push(event);\n bySelector.set(event.target.selector, existing);\n }\n\n for (const [selector, events] of bySelector) {\n if (events.length >= 3) {\n const attributes = events.map((e) => (e.payload as StateChangedPayload).attribute);\n findings.push({\n pattern: 'multiple-state-changes-same-element',\n severity: 'medium',\n description:\n `${events.length} ARIA attributes changed simultaneously on \"${events[0].target.accessibleName}\" ` +\n `(${events[0].target.role}): ${attributes.join(', ')}. ` +\n `Some screen readers announce each attribute change individually, ` +\n `causing a verbose multi-part announcement.`,\n remediation: [\n `Batch attribute changes into a single DOM mutation frame by setting all attributes ` +\n `before the next microtask. Use requestAnimationFrame() or Promise.resolve() to group them.`,\n `Evaluate which attributes actually need to be communicated. For example, ` +\n `if aria-selected changes, the screen reader already announces it; additional ` +\n `aria-checked or aria-pressed changes may be redundant.`,\n `Consider using a single composite state (e.g., just aria-selected for listbox options) ` +\n `rather than multiple state attributes.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'Narrator'],\n relatedEvents: events,\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: selector,\n });\n }\n }\n\n return findings;\n}\n\nfunction detectRapidIdenticalAnnouncements(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const announcements = frame.events.filter((e) => e.type === 'ANNOUNCEMENT');\n\n // Check for identical or near-identical announcement text\n const seen = new Map<string, AccessibilityEvent[]>();\n for (const event of announcements) {\n const text = (event.payload as AnnouncementPayload).text.toLowerCase().trim();\n const existing = seen.get(text) || [];\n existing.push(event);\n seen.set(text, existing);\n }\n\n for (const [text, events] of seen) {\n if (events.length >= 2) {\n findings.push({\n pattern: 'rapid-identical-announcements',\n severity: 'high',\n description:\n `The same live region content (\"${text}\") was announced ${events.length} times ` +\n `within ${frame.end - frame.start}ms. Users will hear the same information repeated.`,\n remediation: [\n `Debounce live region updates. Clear the live region text content first, ` +\n `then set the new value after a 100-200ms delay.`,\n `If updating a live region's textContent to the same value, the screen reader ` +\n `may ignore it OR re-read it depending on implementation. Clear to empty string first.`,\n `Avoid updating the live region inside a loop or rapid event handler. ` +\n `Compute the final state and announce once.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'VoiceOver (iOS)', 'NVDA', 'Narrator'],\n relatedEvents: events,\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: events[0].target.selector,\n });\n }\n }\n\n return findings;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Analyzes a timeline of accessibility events for verbosity issues.\n *\n * Groups events into interaction frames (events within a short time window\n * of each other), then checks each frame for patterns that cause screen\n * readers to announce redundant or duplicate content.\n *\n * @param events - Chronologically ordered accessibility events\n * @param config - Optional configuration overrides\n * @returns A VerbosityReport with all findings and a score\n */\nexport function analyzeVerbosity(\n events: AccessibilityEvent[],\n config?: Partial<VerbosityConfig>\n): VerbosityReport {\n const cfg: VerbosityConfig = { ...DEFAULT_CONFIG, ...config };\n\n // Group events into interaction frames\n const frames = groupIntoFrames(events, cfg.interactionFrameWindow);\n\n // Run all detectors on each frame\n const findings: VerbosityFinding[] = [];\n\n for (const frame of frames) {\n findings.push(...detectRedundantStateAndLiveRegion(frame, cfg));\n findings.push(...detectActiveDescendantPlusStateChange(frame, cfg));\n findings.push(...detectNameChangePlusLiveRegion(frame, cfg));\n findings.push(...detectFocusPlusActiveDescendant(frame, cfg));\n findings.push(...detectMultipleStateChangesSameElement(frame, cfg));\n findings.push(...detectRapidIdenticalAnnouncements(frame, cfg));\n }\n\n // Sort by severity (high first)\n const severityOrder: Record<VerbositySeverity, number> = { high: 0, medium: 1, low: 2 };\n findings.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);\n\n // Compute summary\n const summary = {\n high: findings.filter((f) => f.severity === 'high').length,\n medium: findings.filter((f) => f.severity === 'medium').length,\n low: findings.filter((f) => f.severity === 'low').length,\n total: findings.length,\n };\n\n // Score: 100 (perfect) minus weighted deductions\n const deductions = summary.high * 25 + summary.medium * 10 + summary.low * 3;\n const score = Math.max(0, 100 - deductions);\n\n return { findings, summary, score };\n}\n\n/**\n * Formats a verbosity report as human-readable text output.\n */\nexport function formatVerbosityReport(report: VerbosityReport): string {\n const lines: string[] = [];\n\n lines.push('');\n lines.push('=== VERBOSITY ANALYSIS REPORT ===');\n lines.push('');\n lines.push(`Score: ${report.score}/100 ${report.score >= 80 ? '(Good)' : report.score >= 50 ? '(Needs attention)' : '(Critical verbosity issues)'}`);\n lines.push(`Findings: ${report.summary.total} (${report.summary.high} high, ${report.summary.medium} medium, ${report.summary.low} low)`);\n lines.push('');\n\n if (report.findings.length === 0) {\n lines.push('No verbosity issues detected. Announcements appear clean.');\n return lines.join('\\n');\n }\n\n for (let i = 0; i < report.findings.length; i++) {\n const finding = report.findings[i];\n const severityIcon = finding.severity === 'high' ? '\\u2718' : finding.severity === 'medium' ? '\\u26A0' : '\\u2139';\n\n lines.push(`${severityIcon} [${finding.severity.toUpperCase()}] ${finding.pattern}`);\n lines.push(` Element: ${finding.elementSelector}`);\n lines.push(` Window: ${finding.timeWindow.start}ms - ${finding.timeWindow.end}ms`);\n lines.push(` ${finding.description}`);\n lines.push('');\n lines.push(' Affected: ' + finding.affectedReaders.join(', '));\n lines.push('');\n lines.push(' Remediation:');\n for (const step of finding.remediation) {\n lines.push(` - ${step}`);\n }\n lines.push('');\n\n if (i < report.findings.length - 1) {\n lines.push(' ' + '\\u2500'.repeat(60));\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":["childPath","pc","formatValue","pc","shouldAnnounceRoleFirst","model","computeAccessibleName","buildEventTarget","computeAccessibleName","getElementRole","buildEventTarget","buildEventTarget","buildEventTarget","computeAccessibleName","getElementRole","SPEAKABLE_VERSION","DEFAULT_CONFIG"]}
|
|
1
|
+
{"version":3,"sources":["../src/model/types.ts","../src/model/validation.ts","../src/model/serialization.ts","../src/diff/diff-algorithm.ts","../src/diff/formatter.ts","../src/cli/colors.ts","../src/renderer/nvda-renderer.ts","../src/renderer/jaws-renderer.ts","../src/renderer/voiceover-renderer.ts","../src/renderer/narrator-renderer.ts","../src/renderer/audit-renderer.ts","../src/parser/html-parser.ts","../src/extractor/aria-name.ts","../src/extractor/role-mapper.ts","../src/extractor/state-extractor.ts","../src/extractor/focus-extractor.ts","../src/extractor/tree-builder.ts","../src/runtime/index.ts","../src/runtime/selector.ts","../src/runtime/observers/focus-observer.ts","../src/runtime/observers/mutation-observer.ts","../src/runtime/observers/live-region-observer.ts","../src/runtime/observers/dialog-observer.ts","../src/runtime/engine.ts","../src/runtime/interactions.ts","../src/runtime/heuristics.ts","../src/version.ts","../src/runtime/timeline-generator.ts","../src/runtime/patterns.ts","../src/runtime/serialization.ts","../src/runtime/diff-engine.ts","../src/runtime/severity.ts","../src/runtime/baseline-storage.ts","../src/runtime/verbosity-analyzer.ts"],"sourcesContent":["/**\n * Canonical Announcement Model - Version 1\n * \n * Platform-agnostic representation of accessibility semantics.\n * Deterministic, serializable, suitable for snapshot testing.\n */\n\n/**\n * Model version for forward compatibility.\n * Breaking changes increment major version.\n */\nexport interface ModelVersion {\n major: number;\n minor: number;\n}\n\n/**\n * Accessible role following ARIA specification.\n * V1 supports common interactive and structural roles.\n */\nexport type AccessibleRole =\n // Interactive elements\n | 'button'\n | 'link'\n | 'heading'\n | 'textbox'\n | 'checkbox'\n | 'radio'\n | 'combobox'\n | 'listbox'\n | 'option'\n // Structural\n | 'list'\n | 'listitem'\n | 'article'\n | 'generic'\n // Landmarks\n | 'navigation'\n | 'main'\n | 'banner'\n | 'contentinfo'\n | 'region'\n | 'img'\n | 'complementary'\n | 'form'\n | 'search'\n // Static content (new)\n | 'paragraph'\n | 'blockquote'\n | 'code'\n | 'staticText'\n // Tables (new)\n | 'table'\n | 'row'\n | 'cell'\n | 'columnheader'\n | 'rowheader'\n // Definition lists (new)\n | 'term'\n | 'definition'\n // Figures (new)\n | 'figure'\n | 'caption'\n // Grouping & disclosure (new)\n | 'group'\n | 'dialog'\n // Widgets (new)\n | 'meter'\n | 'progressbar'\n | 'status'\n // Embedded content (new)\n | 'document'\n | 'application'\n | 'separator';\n\n/**\n * Accessible states and properties.\n * Only includes properties relevant to the element's role.\n */\nexport interface AccessibleState {\n /** Whether the element is expanded (e.g., accordion, dropdown) */\n expanded?: boolean;\n \n /** Whether the element is checked (checkbox, radio, or mixed state) */\n checked?: boolean | 'mixed';\n \n /** Whether the element is pressed (toggle button) */\n pressed?: boolean | 'mixed';\n \n /** Whether the element is selected (option, tab, etc.) */\n selected?: boolean;\n \n /** Whether the element is disabled */\n disabled?: boolean;\n \n /** Whether the element has invalid input */\n invalid?: boolean;\n \n /** Whether the element is required */\n required?: boolean;\n \n /** Whether the element is read-only */\n readonly?: boolean;\n \n /** Whether the element is busy loading */\n busy?: boolean;\n \n /** Current page/step/location indicator */\n current?: 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | false;\n \n /** Whether the element is grabbed for drag-and-drop */\n grabbed?: boolean;\n \n /** Whether the element is hidden from accessibility tree */\n hidden?: boolean;\n \n /** Heading level (1-6) */\n level?: number;\n \n /** Position in set (1-indexed) for lists, tabs, etc. */\n posinset?: number;\n \n /** Total size of set */\n setsize?: number;\n}\n\n/**\n * Value for form controls and range widgets.\n */\nexport interface AccessibleValue {\n /** Current value */\n current: string | number;\n \n /** Minimum value (for range widgets) */\n min?: number;\n \n /** Maximum value (for range widgets) */\n max?: number;\n \n /** Textual representation (e.g., \"50%\") */\n text?: string;\n}\n\n/**\n * Focusability information.\n */\nexport interface FocusInfo {\n /** Whether the element can receive focus */\n focusable: boolean;\n \n /** Explicit tabindex value (only present if explicitly set) */\n tabindex?: number;\n}\n\n/**\n * Single node in the accessibility tree.\n */\nexport interface AccessibleNode {\n /** ARIA role of the element */\n role: AccessibleRole;\n \n /** Accessible name (computed via ARIA name algorithm) */\n name: string;\n \n /** Accessible description (aria-describedby, title, etc.) */\n description?: string;\n \n /** Value for form controls */\n value?: AccessibleValue;\n \n /** State properties */\n state: AccessibleState;\n \n /** Focus information */\n focus: FocusInfo;\n \n /** Child nodes in the accessibility tree */\n children: AccessibleNode[];\n}\n\n/**\n * Root of the Canonical Announcement Model.\n */\nexport interface AnnouncementModel {\n /** Model version for forward compatibility */\n version: ModelVersion;\n \n /** Root node of the accessibility tree */\n root: AccessibleNode;\n \n /** Metadata about the extraction */\n metadata: {\n /** ISO 8601 timestamp of extraction */\n extractedAt: string;\n \n /** Optional hash of source HTML for change detection */\n sourceHash?: string;\n };\n}\n\n/**\n * Supported roles as a constant array for validation.\n */\nexport const SUPPORTED_ROLES: readonly AccessibleRole[] = [\n // Original roles (22)\n 'button',\n 'link',\n 'heading',\n 'textbox',\n 'checkbox',\n 'radio',\n 'combobox',\n 'listbox',\n 'option',\n 'list',\n 'listitem',\n 'navigation',\n 'main',\n 'banner',\n 'contentinfo',\n 'region',\n 'img',\n 'article',\n 'complementary',\n 'form',\n 'search',\n 'generic',\n // New roles (21)\n 'paragraph',\n 'blockquote',\n 'code',\n 'staticText',\n 'table',\n 'row',\n 'cell',\n 'columnheader',\n 'rowheader',\n 'term',\n 'definition',\n 'figure',\n 'caption',\n 'group',\n 'dialog',\n 'meter',\n 'progressbar',\n 'status',\n 'document',\n 'application',\n 'separator',\n] as const;\n\n/**\n * Current model version constant.\n */\nexport const CURRENT_MODEL_VERSION: ModelVersion = {\n major: 1,\n minor: 0,\n};\n","/**\n * Validation functions for the Canonical Announcement Model.\n */\n\nimport type {\n AccessibleNode,\n AccessibleRole,\n AccessibleState,\n AnnouncementModel,\n} from './types.js';\nimport { SUPPORTED_ROLES } from './types.js';\n\n/**\n * Validation error class.\n */\nexport class ValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Validates that a role is supported in V1.\n * \n * @param role - The role to validate\n * @returns true if valid\n * @throws ValidationError if invalid\n */\nexport function validateRole(role: string): role is AccessibleRole {\n if (!SUPPORTED_ROLES.includes(role as AccessibleRole)) {\n throw new ValidationError(\n `Invalid role: \"${role}\". Supported roles: ${SUPPORTED_ROLES.join(', ')}`\n );\n }\n return true;\n}\n\n/**\n * Validates accessible state constraints.\n * \n * @param state - The state object to validate\n * @throws ValidationError if invalid\n */\nexport function validateState(state: AccessibleState): void {\n // Validate level is in range 1-6 for headings\n if (state.level !== undefined) {\n if (!Number.isInteger(state.level) || state.level < 1 || state.level > 6) {\n throw new ValidationError(\n `Invalid heading level: ${state.level}. Must be an integer between 1 and 6.`\n );\n }\n }\n\n // Validate posinset is positive\n if (state.posinset !== undefined) {\n if (!Number.isInteger(state.posinset) || state.posinset < 1) {\n throw new ValidationError(\n `Invalid posinset: ${state.posinset}. Must be a positive integer.`\n );\n }\n }\n\n // Validate setsize is positive\n if (state.setsize !== undefined) {\n if (!Number.isInteger(state.setsize) || state.setsize < 1) {\n throw new ValidationError(\n `Invalid setsize: ${state.setsize}. Must be a positive integer.`\n );\n }\n }\n\n // Validate posinset <= setsize if both present\n if (\n state.posinset !== undefined &&\n state.setsize !== undefined &&\n state.posinset > state.setsize\n ) {\n throw new ValidationError(\n `Invalid set position: posinset (${state.posinset}) cannot exceed setsize (${state.setsize}).`\n );\n }\n\n // Validate checked is boolean or 'mixed'\n if (state.checked !== undefined) {\n if (typeof state.checked !== 'boolean' && state.checked !== 'mixed') {\n throw new ValidationError(\n `Invalid checked value: ${state.checked}. Must be boolean or 'mixed'.`\n );\n }\n }\n\n // Validate pressed is boolean or 'mixed'\n if (state.pressed !== undefined) {\n if (typeof state.pressed !== 'boolean' && state.pressed !== 'mixed') {\n throw new ValidationError(\n `Invalid pressed value: ${state.pressed}. Must be boolean or 'mixed'.`\n );\n }\n }\n\n // Validate current is valid enum value\n if (state.current !== undefined) {\n const validCurrentValues = ['page', 'step', 'location', 'date', 'time', 'true', false];\n if (!validCurrentValues.includes(state.current as any)) {\n throw new ValidationError(\n `Invalid current value: ${state.current}. Must be one of: ${validCurrentValues.join(', ')}`\n );\n }\n }\n}\n\n/**\n * Validates tree structure integrity (no cycles).\n * \n * @param node - The root node to validate\n * @param visited - Set of visited nodes (for cycle detection)\n * @throws ValidationError if cycles detected\n */\nexport function validateTreeStructure(\n node: AccessibleNode,\n visited: Set<AccessibleNode> = new Set()\n): void {\n // Check for cycles\n if (visited.has(node)) {\n throw new ValidationError(\n 'Circular reference detected in accessibility tree. Tree must be acyclic.'\n );\n }\n\n visited.add(node);\n\n // Validate role\n validateRole(node.role);\n\n // Validate state\n validateState(node.state);\n\n // Recursively validate children\n for (const child of node.children) {\n validateTreeStructure(child, new Set(visited));\n }\n}\n\n/**\n * Validates an entire AnnouncementModel.\n * \n * @param model - The model to validate\n * @throws ValidationError if invalid\n */\nexport function validateModel(model: AnnouncementModel): void {\n // Validate version\n if (!model.version || typeof model.version.major !== 'number' || typeof model.version.minor !== 'number') {\n throw new ValidationError('Invalid model version. Must have major and minor number fields.');\n }\n\n // Validate metadata\n if (!model.metadata || !model.metadata.extractedAt) {\n throw new ValidationError('Invalid metadata. Must have extractedAt timestamp.');\n }\n\n // Validate timestamp is ISO 8601\n const timestamp = new Date(model.metadata.extractedAt);\n if (isNaN(timestamp.getTime())) {\n throw new ValidationError(\n `Invalid extractedAt timestamp: ${model.metadata.extractedAt}. Must be ISO 8601 format.`\n );\n }\n\n // Validate root node and tree structure\n if (!model.root) {\n throw new ValidationError('Model must have a root node.');\n }\n\n validateTreeStructure(model.root);\n}\n","/**\n * JSON serialization and deserialization for the Canonical Announcement Model.\n * \n * Ensures deterministic output with consistent property ordering.\n */\n\nimport type { AnnouncementModel, AccessibleNode } from './types.js';\nimport { CURRENT_MODEL_VERSION } from './types.js';\nimport { validateModel } from './validation.js';\n\n/**\n * Serialization options.\n */\nexport interface SerializationOptions {\n /** Whether to pretty-print the JSON output */\n pretty?: boolean;\n \n /** Whether to validate the model before serialization */\n validate?: boolean;\n}\n\n/**\n * Deserialization options.\n */\nexport interface DeserializationOptions {\n /** Whether to validate the model after deserialization */\n validate?: boolean;\n}\n\n/**\n * Sorts object keys to ensure deterministic JSON output.\n * \n * @param obj - Object to sort\n * @returns New object with sorted keys\n */\nfunction sortObjectKeys<T extends Record<string, any>>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys) as any as T;\n }\n\n const sorted: Record<string, any> = {};\n const keys = Object.keys(obj).sort();\n\n for (const key of keys) {\n const value = obj[key];\n sorted[key] = typeof value === 'object' && value !== null \n ? sortObjectKeys(value) \n : value;\n }\n\n return sorted as T;\n}\n\n/**\n * Serializes an AnnouncementModel to JSON string.\n * \n * Produces deterministic output with consistent property ordering.\n * \n * @param model - The model to serialize\n * @param options - Serialization options\n * @returns JSON string representation\n * @throws ValidationError if validation is enabled and model is invalid\n */\nexport function serializeModel(\n model: AnnouncementModel,\n options: SerializationOptions = {}\n): string {\n const { pretty = false, validate = true } = options;\n\n // Validate model if requested\n if (validate) {\n validateModel(model);\n }\n\n // Sort keys for deterministic output\n const sorted = sortObjectKeys(model);\n\n // Serialize with optional pretty printing\n return pretty \n ? JSON.stringify(sorted, null, 2)\n : JSON.stringify(sorted);\n}\n\n/**\n * Deserializes a JSON string to an AnnouncementModel.\n * \n * @param json - JSON string to deserialize\n * @param options - Deserialization options\n * @returns Parsed AnnouncementModel\n * @throws SyntaxError if JSON is invalid\n * @throws ValidationError if validation is enabled and model is invalid\n */\nexport function deserializeModel(\n json: string,\n options: DeserializationOptions = {}\n): AnnouncementModel {\n const { validate = true } = options;\n\n // Parse JSON\n const model = JSON.parse(json) as AnnouncementModel;\n\n // Validate model if requested\n if (validate) {\n validateModel(model);\n }\n\n return model;\n}\n\n/**\n * Creates a new AnnouncementModel with current version and timestamp.\n * \n * @param root - Root accessible node\n * @param sourceHash - Optional hash of source HTML\n * @returns New AnnouncementModel\n */\nexport function createModel(\n root: AccessibleNode,\n sourceHash?: string\n): AnnouncementModel {\n return {\n version: { ...CURRENT_MODEL_VERSION },\n root,\n metadata: {\n extractedAt: new Date().toISOString(),\n ...(sourceHash && { sourceHash }),\n },\n };\n}\n\n/**\n * Compares two models for equality (deep comparison).\n * \n * @param a - First model\n * @param b - Second model\n * @returns true if models are equivalent\n */\nexport function modelsEqual(a: AnnouncementModel, b: AnnouncementModel): boolean {\n // Simple approach: serialize both and compare strings\n // This works because serialization is deterministic\n const jsonA = serializeModel(a, { validate: false });\n const jsonB = serializeModel(b, { validate: false });\n return jsonA === jsonB;\n}\n\n/**\n * Clones a model (deep copy).\n * \n * @param model - Model to clone\n * @returns Deep copy of the model\n */\nexport function cloneModel(model: AnnouncementModel): AnnouncementModel {\n const json = serializeModel(model, { validate: false });\n return deserializeModel(json, { validate: false });\n}\n","/**\n * Semantic diff algorithm for accessibility trees.\n * \n * Compares two accessibility trees and identifies:\n * - Added nodes (present in new tree, not in old)\n * - Removed nodes (present in old tree, not in new)\n * - Changed nodes (same path, different properties)\n */\n\nimport type { AccessibleNode, AccessibleState, AccessibleValue, FocusInfo } from '../model/types.js';\nimport type { SemanticDiff, NodeChange, PropertyChange, NodePath } from './types.js';\n\n/**\n * Compare two accessibility trees and generate a semantic diff.\n * \n * @param oldTree - The original accessibility tree\n * @param newTree - The updated accessibility tree\n * @returns Semantic diff with all detected changes\n */\nexport function diffAccessibilityTrees(\n oldTree: AccessibleNode,\n newTree: AccessibleNode\n): SemanticDiff {\n const changes: NodeChange[] = [];\n \n // Build maps of path -> node for both trees\n const oldNodes = buildNodeMap(oldTree, 'root');\n const newNodes = buildNodeMap(newTree, 'root');\n \n // Find removed nodes (in old but not in new)\n for (const [path, node] of oldNodes) {\n if (!newNodes.has(path)) {\n changes.push({\n type: 'removed',\n path,\n node,\n });\n }\n }\n \n // Find added nodes (in new but not in old)\n for (const [path, node] of newNodes) {\n if (!oldNodes.has(path)) {\n changes.push({\n type: 'added',\n path,\n node,\n });\n }\n }\n \n // Find changed nodes (in both but with different properties)\n for (const [path, oldNode] of oldNodes) {\n const newNode = newNodes.get(path);\n if (newNode) {\n const propertyChanges = compareNodes(oldNode, newNode);\n if (propertyChanges.length > 0) {\n changes.push({\n type: 'changed',\n path,\n changes: propertyChanges,\n });\n }\n }\n }\n \n // Sort changes by path for deterministic output\n changes.sort((a, b) => a.path.localeCompare(b.path));\n \n // Calculate summary statistics\n const summary = {\n added: changes.filter(c => c.type === 'added').length,\n removed: changes.filter(c => c.type === 'removed').length,\n changed: changes.filter(c => c.type === 'changed').length,\n total: changes.length,\n };\n \n return { changes, summary };\n}\n\n/**\n * Build a map of path -> node for a tree.\n * \n * @param node - Root node of the tree\n * @param path - Current path (starts with 'root')\n * @returns Map of paths to nodes\n */\nfunction buildNodeMap(\n node: AccessibleNode,\n path: NodePath\n): Map<NodePath, AccessibleNode> {\n const map = new Map<NodePath, AccessibleNode>();\n \n // Add current node\n map.set(path, node);\n \n // Recursively add children\n node.children.forEach((child, index) => {\n const childPath = `${path}.children[${index}]`;\n const childMap = buildNodeMap(child, childPath);\n for (const [childPath, childNode] of childMap) {\n map.set(childPath, childNode);\n }\n });\n \n return map;\n}\n\n/**\n * Compare two nodes and identify property changes.\n * \n * @param oldNode - Original node\n * @param newNode - Updated node\n * @returns Array of property changes\n */\nfunction compareNodes(\n oldNode: AccessibleNode,\n newNode: AccessibleNode\n): PropertyChange[] {\n const changes: PropertyChange[] = [];\n \n // Compare role\n if (oldNode.role !== newNode.role) {\n changes.push({\n property: 'role',\n oldValue: oldNode.role,\n newValue: newNode.role,\n });\n }\n \n // Compare name\n if (oldNode.name !== newNode.name) {\n changes.push({\n property: 'name',\n oldValue: oldNode.name,\n newValue: newNode.name,\n });\n }\n \n // Compare description\n if (oldNode.description !== newNode.description) {\n changes.push({\n property: 'description',\n oldValue: oldNode.description,\n newValue: newNode.description,\n });\n }\n \n // Compare value\n if (!valuesEqual(oldNode.value, newNode.value)) {\n changes.push({\n property: 'value',\n oldValue: oldNode.value,\n newValue: newNode.value,\n });\n }\n \n // Compare state\n if (!statesEqual(oldNode.state, newNode.state)) {\n changes.push({\n property: 'state',\n oldValue: oldNode.state,\n newValue: newNode.state,\n });\n }\n \n // Compare focus\n if (!focusEqual(oldNode.focus, newNode.focus)) {\n changes.push({\n property: 'focus',\n oldValue: oldNode.focus,\n newValue: newNode.focus,\n });\n }\n \n return changes;\n}\n\n/**\n * Compare two AccessibleValue objects for equality.\n */\nfunction valuesEqual(\n a: AccessibleValue | undefined,\n b: AccessibleValue | undefined\n): boolean {\n if (a === undefined && b === undefined) return true;\n if (a === undefined || b === undefined) return false;\n \n return (\n a.current === b.current &&\n a.min === b.min &&\n a.max === b.max &&\n a.text === b.text\n );\n}\n\n/**\n * Compare two AccessibleState objects for equality.\n */\nfunction statesEqual(\n a: AccessibleState,\n b: AccessibleState\n): boolean {\n // Get all unique keys from both states\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n \n for (const key of keys) {\n const aValue = a[key as keyof AccessibleState];\n const bValue = b[key as keyof AccessibleState];\n \n if (aValue !== bValue) {\n return false;\n }\n }\n \n return true;\n}\n\n/**\n * Compare two FocusInfo objects for equality.\n */\nfunction focusEqual(\n a: FocusInfo,\n b: FocusInfo\n): boolean {\n return (\n a.focusable === b.focusable &&\n a.tabindex === b.tabindex\n );\n}\n\n/**\n * Generate a human-readable description of a change.\n * \n * @param change - The change to describe\n * @returns Human-readable description\n */\nexport function describeChange(change: NodeChange): string {\n switch (change.type) {\n case 'added':\n return `Added ${change.node?.role} \"${change.node?.name}\" at ${change.path}`;\n \n case 'removed':\n return `Removed ${change.node?.role} \"${change.node?.name}\" from ${change.path}`;\n \n case 'changed': {\n const descriptions = change.changes?.map(pc => {\n const oldVal = formatValue(pc.oldValue);\n const newVal = formatValue(pc.newValue);\n return `${pc.property}: ${oldVal} → ${newVal}`;\n }) || [];\n return `Changed at ${change.path}: ${descriptions.join(', ')}`;\n }\n \n default:\n return `Unknown change at ${change.path}`;\n }\n}\n\n/**\n * Format a value for display in change descriptions.\n */\nfunction formatValue(value: unknown): string {\n if (value === undefined) return 'undefined';\n if (value === null) return 'null';\n if (typeof value === 'string') return `\"${value}\"`;\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n}\n","/**\n * Formatting utilities for semantic diff output.\n * \n * Provides JSON and human-readable text formatting for diffs.\n */\n\nimport type { SemanticDiff, PropertyChange } from './types.js';\n\n/**\n * Format a semantic diff as pretty-printed JSON.\n * \n * @param diff - The semantic diff to format\n * @returns JSON string with 2-space indentation\n */\nexport function formatDiffAsJSON(diff: SemanticDiff): string {\n return JSON.stringify(diff, null, 2);\n}\n\n/**\n * Format a semantic diff as human-readable text.\n * \n * @param diff - The semantic diff to format\n * @returns Multi-line text description of changes\n */\nexport function formatDiffAsText(diff: SemanticDiff): string {\n const lines: string[] = [];\n \n // Summary header\n lines.push('=== Accessibility Tree Diff ===');\n lines.push('');\n lines.push(`Total changes: ${diff.summary.total}`);\n lines.push(` Added: ${diff.summary.added}`);\n lines.push(` Removed: ${diff.summary.removed}`);\n lines.push(` Changed: ${diff.summary.changed}`);\n lines.push('');\n \n if (diff.changes.length === 0) {\n lines.push('No changes detected.');\n return lines.join('\\n');\n }\n \n // Group changes by type\n const added = diff.changes.filter(c => c.type === 'added');\n const removed = diff.changes.filter(c => c.type === 'removed');\n const changed = diff.changes.filter(c => c.type === 'changed');\n \n // Added nodes\n if (added.length > 0) {\n lines.push('--- Added Nodes ---');\n for (const change of added) {\n lines.push(`+ ${change.path}`);\n lines.push(` Role: ${change.node?.role}`);\n lines.push(` Name: \"${change.node?.name}\"`);\n if (change.node?.description) {\n lines.push(` Description: \"${change.node.description}\"`);\n }\n lines.push('');\n }\n }\n \n // Removed nodes\n if (removed.length > 0) {\n lines.push('--- Removed Nodes ---');\n for (const change of removed) {\n lines.push(`- ${change.path}`);\n lines.push(` Role: ${change.node?.role}`);\n lines.push(` Name: \"${change.node?.name}\"`);\n if (change.node?.description) {\n lines.push(` Description: \"${change.node.description}\"`);\n }\n lines.push('');\n }\n }\n \n // Changed nodes\n if (changed.length > 0) {\n lines.push('--- Changed Nodes ---');\n for (const change of changed) {\n lines.push(`~ ${change.path}`);\n if (change.changes) {\n for (const propChange of change.changes) {\n lines.push(` ${formatPropertyChange(propChange)}`);\n }\n }\n lines.push('');\n }\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Format a single property change as text.\n */\nfunction formatPropertyChange(change: PropertyChange): string {\n const oldVal = formatValue(change.oldValue);\n const newVal = formatValue(change.newValue);\n return `${change.property}: ${oldVal} → ${newVal}`;\n}\n\n/**\n * Format a value for display.\n */\nfunction formatValue(value: unknown): string {\n if (value === undefined) return 'undefined';\n if (value === null) return 'null';\n if (typeof value === 'string') return `\"${value}\"`;\n if (typeof value === 'object') {\n // For objects, show a compact representation\n const json = JSON.stringify(value);\n if (json.length > 50) {\n return json.substring(0, 47) + '...';\n }\n return json;\n }\n return String(value);\n}\n\n/**\n * Format a semantic diff for CI/CD tools (GitHub Actions, GitLab CI, etc.).\n * \n * Uses a format that's easy to parse and diff-friendly.\n * \n * @param diff - The semantic diff to format\n * @returns CI-friendly text output\n */\nexport function formatDiffForCI(diff: SemanticDiff): string {\n const lines: string[] = [];\n \n // Machine-readable summary line\n lines.push(`DIFF_SUMMARY: added=${diff.summary.added} removed=${diff.summary.removed} changed=${diff.summary.changed} total=${diff.summary.total}`);\n lines.push('');\n \n // One line per change for easy parsing\n for (const change of diff.changes) {\n switch (change.type) {\n case 'added':\n lines.push(`ADDED: ${change.path} | role=${change.node?.role} | name=\"${change.node?.name}\"`);\n break;\n \n case 'removed':\n lines.push(`REMOVED: ${change.path} | role=${change.node?.role} | name=\"${change.node?.name}\"`);\n break;\n \n case 'changed':\n const props = change.changes?.map(pc => \n `${pc.property}:${formatValue(pc.oldValue)}->${formatValue(pc.newValue)}`\n ).join(' | ') || '';\n lines.push(`CHANGED: ${change.path} | ${props}`);\n break;\n }\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Check if a diff represents a regression (accessibility got worse).\n * \n * Heuristics:\n * - Removed nodes with important roles (button, link, heading, etc.)\n * - Changed nodes that lost accessible names\n * - Changed nodes that became disabled or hidden\n * \n * @param diff - The semantic diff to analyze\n * @returns True if potential regression detected\n */\nexport function hasAccessibilityRegression(diff: SemanticDiff): boolean {\n const importantRoles = new Set([\n 'button', 'link', 'heading', 'textbox', 'checkbox', 'radio',\n 'navigation', 'main', 'banner', 'contentinfo', 'form', 'search'\n ]);\n \n // Check for removed important nodes\n for (const change of diff.changes) {\n if (change.type === 'removed' && change.node?.role && importantRoles.has(change.node.role)) {\n return true;\n }\n \n // Check for nodes that lost their accessible name\n if (change.type === 'changed' && change.changes) {\n for (const propChange of change.changes) {\n if (propChange.property === 'name') {\n const oldName = propChange.oldValue as string;\n const newName = propChange.newValue as string;\n if (oldName && !newName) {\n return true;\n }\n }\n \n // Check for nodes that became hidden or disabled\n if (propChange.property === 'state') {\n const oldState = propChange.oldValue as any;\n const newState = propChange.newValue as any;\n if (!oldState?.hidden && newState?.hidden) {\n return true;\n }\n if (!oldState?.disabled && newState?.disabled) {\n return true;\n }\n }\n }\n }\n }\n \n return false;\n}\n","import pc from 'picocolors';\n\nexport interface ColorFunctions {\n // Semantic colors for audit report\n error: (s: string) => string;\n warning: (s: string) => string;\n info: (s: string) => string;\n success: (s: string) => string;\n heading: (s: string) => string;\n title: (s: string) => string;\n dim: (s: string) => string;\n\n // Semantic colors for screen reader output\n roleName: (s: string) => string;\n stateName: (s: string) => string;\n elementName: (s: string) => string;\n sectionHeader: (s: string) => string;\n description: (s: string) => string;\n\n // Utility\n bold: (s: string) => string;\n enabled: boolean;\n}\n\nconst identity = (s: string): string => s;\n\n/** Check if color output should be enabled for a given stream */\nexport function isColorEnabled(stream: { isTTY?: boolean }): boolean {\n return stream.isTTY === true;\n}\n\n/** Create a set of color functions, either active or passthrough */\nexport function createColors(enabled: boolean): ColorFunctions {\n if (!enabled) {\n return {\n error: identity,\n warning: identity,\n info: identity,\n success: identity,\n heading: identity,\n title: identity,\n dim: identity,\n roleName: identity,\n stateName: identity,\n elementName: identity,\n sectionHeader: identity,\n description: identity,\n bold: identity,\n enabled: false,\n };\n }\n\n return {\n error: pc.red,\n warning: pc.yellow,\n info: pc.blue,\n success: pc.green,\n heading: (s: string) => pc.bold(pc.cyan(s)),\n title: (s: string) => pc.bold(pc.cyan(s)),\n dim: pc.dim,\n roleName: pc.cyan,\n stateName: pc.yellow,\n elementName: (s: string) => pc.bold(pc.white(s)),\n sectionHeader: (s: string) => pc.bold(pc.white(s)),\n description: pc.dim,\n bold: pc.bold,\n enabled: true,\n };\n}\n","/**\n * NVDA screen reader announcement renderer.\n * \n * Generates heuristic announcement text approximating NVDA output.\n * This is NOT a perfect emulation - real NVDA behavior varies by version,\n * settings, and context. Use for development guidance only.\n */\n\nimport type { AccessibleNode, AnnouncementModel } from '../model/types.js';\nimport { createColors, type ColorFunctions } from '../cli/colors.js';\n\n/**\n * Renders an announcement model as NVDA-style announcement text.\n * \n * @param model - Announcement model to render\n * @param colorize - Whether to apply ANSI color codes to the output\n * @returns NVDA-style announcement text\n */\nexport function renderNVDA(model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const announcements: string[] = [];\n renderNodeNVDA(model.root, announcements, c);\n return announcements.join('\\n');\n}\n\n/**\n * Recursively renders a node and its children as NVDA announcements.\n * \n * @param node - Node to render\n * @param announcements - Array to collect announcement strings\n * @param c - Color functions for formatting\n */\nfunction renderNodeNVDA(node: AccessibleNode, announcements: string[], c: ColorFunctions): void {\n const announcement = formatNodeNVDA(node, c);\n if (announcement) {\n announcements.push(announcement);\n }\n \n // Recursively render children, collapsing redundant same-name children\n for (const child of node.children) {\n if (child.name && child.name === node.name && node.children.length === 1) {\n // Skip child that repeats parent name — recurse into grandchildren\n for (const grandchild of child.children) {\n renderNodeNVDA(grandchild, announcements, c);\n }\n continue;\n }\n renderNodeNVDA(child, announcements, c);\n }\n}\n\n/**\n * Formats a single node as an NVDA announcement.\n * \n * @param node - Node to format\n * @param c - Color functions for formatting\n * @returns Formatted announcement string or empty string if node should not be announced\n */\nfunction formatNodeNVDA(node: AccessibleNode, c: ColorFunctions): string {\n const parts: string[] = [];\n \n // Add name (if present)\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n \n // Add role-specific formatting\n const roleText = formatRoleNVDA(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n \n // Add states\n const stateText = formatStatesNVDA(node);\n if (stateText) {\n parts.push(c.stateName(stateText));\n }\n \n // Add value (for form controls)\n if (node.value) {\n const valueText = node.value.text || String(node.value.current);\n if (valueText) {\n parts.push(valueText);\n }\n }\n \n // Add description (if present)\n if (node.description) {\n parts.push(c.description(node.description));\n }\n \n return parts.join(', ');\n}\n\n/**\n * Formats the role portion of an NVDA announcement.\n * \n * @param node - Node to format\n * @returns Role text or empty string\n */\nfunction formatRoleNVDA(node: AccessibleNode): string {\n const role = node.role;\n \n switch (role) {\n case 'button':\n return 'button';\n \n case 'link':\n return 'link';\n \n case 'heading':\n if (node.state.level) {\n return `heading level ${node.state.level}`;\n }\n return 'heading';\n \n case 'textbox':\n return 'edit';\n \n case 'checkbox':\n return 'checkbox';\n \n case 'radio':\n return 'radio button';\n \n case 'combobox':\n return 'combo box';\n \n case 'listbox':\n return 'list box';\n \n case 'option':\n return 'option';\n \n case 'list':\n return 'list';\n \n case 'listitem':\n return 'list item';\n \n case 'navigation':\n return 'navigation landmark';\n \n case 'main':\n return 'main landmark';\n \n case 'banner':\n return 'banner landmark';\n \n case 'contentinfo':\n return 'content information landmark';\n \n case 'region':\n return 'region landmark';\n \n case 'complementary':\n return 'complementary landmark';\n \n case 'form':\n return 'form landmark';\n \n case 'search':\n return 'search landmark';\n \n case 'img':\n return 'graphic';\n \n case 'article':\n return 'article';\n \n case 'generic':\n // Generic containers are typically not announced\n return '';\n \n case 'staticText':\n case 'paragraph':\n case 'cell':\n case 'term':\n case 'definition':\n case 'caption':\n return '';\n \n case 'blockquote':\n return 'block quote';\n \n case 'code':\n return 'code';\n \n case 'table':\n return 'table';\n \n case 'row':\n return 'row';\n \n case 'columnheader':\n return 'column header';\n \n case 'rowheader':\n return 'row header';\n \n case 'figure':\n return 'figure';\n \n case 'dialog':\n return 'dialog';\n \n case 'meter':\n return 'meter';\n \n case 'progressbar':\n return 'progress bar';\n \n case 'status':\n return 'status';\n \n case 'group':\n return node.name ? 'grouping' : '';\n \n case 'document':\n return 'document';\n \n case 'application':\n return 'embedded object';\n \n case 'separator':\n return 'separator';\n \n default:\n return role;\n }\n}\n\n/**\n * Formats the state portion of an NVDA announcement.\n * \n * @param node - Node to format\n * @returns State text or empty string\n */\nfunction formatStatesNVDA(node: AccessibleNode): string {\n const states: string[] = [];\n \n // Expanded/collapsed state\n if (node.state.expanded !== undefined) {\n states.push(node.state.expanded ? 'expanded' : 'collapsed');\n }\n \n // Checked state (checkbox/radio)\n if (node.state.checked !== undefined) {\n if (node.state.checked === 'mixed') {\n states.push('half checked');\n } else {\n states.push(node.state.checked ? 'checked' : 'not checked');\n }\n }\n \n // Pressed state (toggle button)\n if (node.state.pressed !== undefined) {\n if (node.state.pressed === 'mixed') {\n states.push('half pressed');\n } else {\n states.push(node.state.pressed ? 'pressed' : 'not pressed');\n }\n }\n \n // Selected state\n if (node.state.selected !== undefined) {\n states.push(node.state.selected ? 'selected' : 'not selected');\n }\n \n // Disabled state\n if (node.state.disabled) {\n states.push('unavailable');\n }\n \n // Invalid state\n if (node.state.invalid) {\n states.push('invalid entry');\n }\n \n // Required state\n if (node.state.required) {\n states.push('required');\n }\n \n // Read-only state\n if (node.state.readonly) {\n states.push('read only');\n }\n \n // Busy state\n if (node.state.busy) {\n states.push('busy');\n }\n \n // Current state\n if (node.state.current) {\n if (node.state.current === 'page') {\n states.push('current page');\n } else if (node.state.current === 'step') {\n states.push('current step');\n } else if (node.state.current === 'location') {\n states.push('current location');\n } else if (node.state.current === 'date') {\n states.push('current date');\n } else if (node.state.current === 'time') {\n states.push('current time');\n } else if (node.state.current === 'true') {\n states.push('current');\n }\n }\n \n // Grabbed state (drag and drop)\n if (node.state.grabbed !== undefined) {\n states.push(node.state.grabbed ? 'grabbed' : 'not grabbed');\n }\n \n return states.join(', ');\n}\n","/**\n * JAWS screen reader announcement renderer.\n * \n * Generates heuristic announcement text approximating JAWS output.\n * This is NOT a perfect emulation - real JAWS behavior varies by version,\n * settings, verbosity level, and context. Use for development guidance only.\n */\n\nimport type { AccessibleNode, AnnouncementModel } from '../model/types.js';\nimport { createColors, type ColorFunctions } from '../cli/colors.js';\n\n/**\n * Renders an announcement model as JAWS-style announcement text.\n * \n * @param model - Announcement model to render\n * @param colorize - Whether to apply ANSI color codes to the output\n * @returns JAWS-style announcement text\n */\nexport function renderJAWS(model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const announcements: string[] = [];\n renderNodeJAWS(model.root, announcements, c);\n return announcements.join('\\n');\n}\n\n/**\n * Recursively renders a node and its children as JAWS announcements.\n * \n * @param node - Node to render\n * @param announcements - Array to collect announcement strings\n * @param c - Color functions for formatting\n */\nfunction renderNodeJAWS(node: AccessibleNode, announcements: string[], c: ColorFunctions): void {\n const announcement = formatNodeJAWS(node, c);\n if (announcement) {\n announcements.push(announcement);\n }\n \n // Recursively render children, collapsing redundant same-name children\n for (const child of node.children) {\n if (child.name && child.name === node.name && node.children.length === 1) {\n for (const grandchild of child.children) {\n renderNodeJAWS(grandchild, announcements, c);\n }\n continue;\n }\n renderNodeJAWS(child, announcements, c);\n }\n}\n\n/**\n * Formats a single node as a JAWS announcement.\n * \n * @param node - Node to format\n * @param c - Color functions for formatting\n * @returns Formatted announcement string or empty string if node should not be announced\n */\nfunction formatNodeJAWS(node: AccessibleNode, c: ColorFunctions): string {\n const parts: string[] = [];\n \n // Add name (if present)\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n \n // Add role-specific formatting\n const roleText = formatRoleJAWS(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n \n // Add states\n const stateText = formatStatesJAWS(node);\n if (stateText) {\n parts.push(c.stateName(stateText));\n }\n \n // Add value (for form controls)\n if (node.value) {\n const valueText = node.value.text || String(node.value.current);\n if (valueText) {\n parts.push(valueText);\n }\n }\n \n // Add description (if present)\n if (node.description) {\n parts.push(c.description(node.description));\n }\n \n return parts.join(', ');\n}\n\n/**\n * Formats the role portion of a JAWS announcement.\n * \n * @param node - Node to format\n * @returns Role text or empty string\n */\nfunction formatRoleJAWS(node: AccessibleNode): string {\n const role = node.role;\n \n switch (role) {\n case 'button':\n return 'button';\n \n case 'link':\n // JAWS uses \"clickable\" for links\n return 'clickable';\n \n case 'heading':\n if (node.state.level) {\n return `heading ${node.state.level}`;\n }\n return 'heading';\n \n case 'textbox':\n return 'edit';\n \n case 'checkbox':\n return 'check box';\n \n case 'radio':\n return 'radio button';\n \n case 'combobox':\n // JAWS uses \"combo box\" (two words)\n return 'combo box';\n \n case 'listbox':\n return 'list box';\n \n case 'option':\n return 'option';\n \n case 'list':\n return 'list';\n \n case 'listitem':\n return 'list item';\n \n case 'navigation':\n return 'navigation region';\n \n case 'main':\n return 'main region';\n \n case 'banner':\n return 'banner region';\n \n case 'contentinfo':\n return 'content information region';\n \n case 'region':\n return 'region';\n \n case 'img':\n return 'graphic';\n \n case 'article':\n return 'article';\n \n case 'complementary':\n return 'complementary region';\n \n case 'form':\n return 'form';\n \n case 'search':\n return 'search region';\n \n case 'generic':\n // Generic containers typically not announced\n return '';\n \n case 'staticText':\n case 'paragraph':\n case 'term':\n case 'definition':\n case 'caption':\n return '';\n \n case 'blockquote':\n return 'block quote';\n \n case 'code':\n return 'code';\n \n case 'table': {\n const rows = node.children.filter(c => c.role === 'row');\n const rowCount = rows.length;\n const colCount = rows.length > 0 ? rows[0].children.length : 0;\n return `table with ${rowCount} rows and ${colCount} columns`;\n }\n \n case 'row': {\n const pos = node.state.posinset ?? 0;\n return `row ${pos}`;\n }\n \n case 'cell': {\n const pos = node.state.posinset ?? 0;\n return `column ${pos}`;\n }\n \n case 'columnheader':\n return 'column header';\n \n case 'rowheader':\n return 'row header';\n \n case 'figure':\n return 'figure';\n \n case 'dialog':\n return 'dialog';\n \n case 'meter':\n return 'meter';\n \n case 'progressbar':\n return 'progress bar';\n \n case 'status':\n return 'status';\n \n case 'group':\n return node.name ? 'group' : '';\n \n case 'document':\n return 'frame';\n \n case 'application':\n return 'embedded object';\n \n case 'separator':\n return 'separator';\n \n default:\n return role;\n }\n}\n\n/**\n * Formats the state portion of a JAWS announcement.\n * \n * @param node - Node to format\n * @returns State text or empty string\n */\nfunction formatStatesJAWS(node: AccessibleNode): string {\n const states: string[] = [];\n \n // Expanded/collapsed\n if (node.state.expanded !== undefined) {\n states.push(node.state.expanded ? 'expanded' : 'collapsed');\n }\n \n // Checked state (checkbox, radio)\n if (node.state.checked !== undefined) {\n if (node.state.checked === 'mixed') {\n states.push('partially checked');\n } else if (node.state.checked) {\n states.push('checked');\n } else {\n states.push('not checked');\n }\n }\n \n // Pressed state (toggle button)\n if (node.state.pressed !== undefined) {\n if (node.state.pressed === 'mixed') {\n states.push('partially pressed');\n } else if (node.state.pressed) {\n states.push('pressed');\n } else {\n states.push('not pressed');\n }\n }\n \n // Selected state\n if (node.state.selected !== undefined) {\n states.push(node.state.selected ? 'selected' : 'not selected');\n }\n \n // Disabled state\n if (node.state.disabled) {\n states.push('unavailable');\n }\n \n // Invalid state\n if (node.state.invalid) {\n states.push('invalid entry');\n }\n \n // Required state\n if (node.state.required) {\n states.push('required');\n }\n \n // Read-only state\n if (node.state.readonly) {\n states.push('read only');\n }\n \n // Busy state\n if (node.state.busy) {\n states.push('busy');\n }\n \n // Current state\n if (node.state.current) {\n switch (node.state.current) {\n case 'page':\n states.push('current page');\n break;\n case 'step':\n states.push('current step');\n break;\n case 'location':\n states.push('current location');\n break;\n case 'date':\n states.push('current date');\n break;\n case 'time':\n states.push('current time');\n break;\n case 'true':\n states.push('current');\n break;\n }\n }\n \n // Grabbed state (drag and drop)\n if (node.state.grabbed !== undefined) {\n states.push(node.state.grabbed ? 'grabbed' : 'not grabbed');\n }\n \n return states.join(', ');\n}\n","/**\n * VoiceOver screen reader announcement renderer.\n * \n * Generates heuristic announcement text approximating VoiceOver output.\n * This is NOT a perfect emulation - real VoiceOver behavior varies by version,\n * settings, and context. Use for development guidance only.\n */\n\nimport type { AccessibleNode, AccessibleRole, AnnouncementModel } from '../model/types.js';\nimport { createColors, type ColorFunctions } from '../cli/colors.js';\n\n/**\n * Renders an announcement model as VoiceOver-style announcement text.\n * \n * @param model - Announcement model to render\n * @param colorize - Whether to apply ANSI color codes to the output\n * @returns VoiceOver-style announcement text\n */\nexport function renderVoiceOver(model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const announcements: string[] = [];\n renderNodeVoiceOver(model.root, announcements, c);\n return announcements.join('\\n');\n}\n\n/**\n * Recursively renders a node and its children as VoiceOver announcements.\n * \n * @param node - Node to render\n * @param announcements - Array to collect announcement strings\n * @param c - Color functions for formatting\n */\nfunction renderNodeVoiceOver(node: AccessibleNode, announcements: string[], c: ColorFunctions): void {\n const announcement = formatNodeVoiceOver(node, c);\n if (announcement) {\n announcements.push(announcement);\n }\n \n // Recursively render children, collapsing redundant same-name children\n for (const child of node.children) {\n if (child.name && child.name === node.name && node.children.length === 1) {\n for (const grandchild of child.children) {\n renderNodeVoiceOver(grandchild, announcements, c);\n }\n continue;\n }\n renderNodeVoiceOver(child, announcements, c);\n }\n}\n\n/**\n * Formats a single node as a VoiceOver announcement.\n * \n * @param node - Node to format\n * @param c - Color functions for formatting\n * @returns Formatted announcement string or empty string if node should not be announced\n */\nfunction formatNodeVoiceOver(node: AccessibleNode, c: ColorFunctions): string {\n const parts: string[] = [];\n \n // VoiceOver often announces role before name for some elements\n const roleFirst = shouldAnnounceRoleFirst(node.role);\n \n if (roleFirst) {\n // Add role first\n const roleText = formatRoleVoiceOver(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n \n // Then name\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n } else {\n // Add name first\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n \n // Then role\n const roleText = formatRoleVoiceOver(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n }\n \n // Add states\n const stateText = formatStatesVoiceOver(node);\n if (stateText) {\n parts.push(c.stateName(stateText));\n }\n \n // Add value (for form controls)\n if (node.value) {\n const valueText = node.value.text || String(node.value.current);\n if (valueText) {\n parts.push(valueText);\n }\n }\n \n // Add description (if present)\n if (node.description) {\n parts.push(c.description(node.description));\n }\n \n return parts.join(', ');\n}\n\n/**\n * Determines if role should be announced before name.\n * \n * VoiceOver announces role first for headings and some landmarks.\n * \n * @param role - Role to check\n * @returns true if role should be announced first\n */\nfunction shouldAnnounceRoleFirst(role: AccessibleRole): boolean {\n return role === 'heading' || \n role === 'navigation' ||\n role === 'main' ||\n role === 'banner' ||\n role === 'contentinfo' ||\n role === 'complementary' ||\n role === 'region' ||\n role === 'form' ||\n role === 'search' ||\n role === 'blockquote' ||\n role === 'figure' ||\n role === 'dialog' ||\n role === 'group' ||\n role === 'document';\n}\n\n/**\n * Formats the role portion of a VoiceOver announcement.\n * \n * @param node - Node to format\n * @returns Role text or empty string\n */\nfunction formatRoleVoiceOver(node: AccessibleNode): string {\n const role = node.role;\n \n switch (role) {\n case 'button':\n return 'button';\n \n case 'link':\n return 'link';\n \n case 'heading':\n if (node.state.level) {\n return `heading level ${node.state.level}`;\n }\n return 'heading';\n \n case 'textbox':\n return 'edit text';\n \n case 'checkbox':\n return 'checkbox';\n \n case 'radio':\n return 'radio button';\n \n case 'combobox':\n return 'combo box';\n \n case 'listbox':\n return 'list box';\n \n case 'option':\n return 'option';\n \n case 'list':\n return 'list';\n \n case 'listitem':\n return 'item';\n \n case 'navigation':\n return 'navigation';\n \n case 'main':\n return 'main';\n \n case 'banner':\n return 'banner';\n \n case 'contentinfo':\n return 'content information';\n \n case 'region':\n return 'region';\n \n case 'complementary':\n return 'complementary';\n \n case 'form':\n return 'form';\n \n case 'search':\n return 'search';\n \n case 'img':\n return 'image';\n \n case 'article':\n return 'article';\n \n case 'generic':\n // Generic containers are typically not announced\n return '';\n \n case 'staticText':\n case 'paragraph':\n case 'cell':\n case 'term':\n case 'definition':\n case 'caption':\n return '';\n \n case 'blockquote':\n return 'blockquote';\n \n case 'code':\n return 'code';\n \n case 'table': {\n const rows = node.children.filter(c => c.role === 'row');\n const rowCount = rows.length;\n const colCount = rows.length > 0 ? rows[0].children.length : 0;\n return `table, ${rowCount} rows, ${colCount} columns`;\n }\n \n case 'row':\n return 'row';\n \n case 'columnheader':\n return 'column header';\n \n case 'rowheader':\n return 'row header';\n \n case 'figure':\n return 'figure';\n \n case 'dialog':\n return 'web dialog';\n \n case 'meter':\n return 'level indicator';\n \n case 'progressbar':\n return 'progress indicator';\n \n case 'status':\n return 'status';\n \n case 'group':\n return node.name ? 'group' : '';\n \n case 'document':\n return 'frame';\n \n case 'application':\n return 'embedded object';\n \n case 'separator':\n return 'separator';\n \n default:\n return role;\n }\n}\n\n/**\n * Formats the state portion of a VoiceOver announcement.\n * \n * @param node - Node to format\n * @returns State text or empty string\n */\nfunction formatStatesVoiceOver(node: AccessibleNode): string {\n const states: string[] = [];\n \n // Expanded/collapsed state\n if (node.state.expanded !== undefined) {\n states.push(node.state.expanded ? 'expanded' : 'collapsed');\n }\n \n // Checked state (checkbox/radio)\n if (node.state.checked !== undefined) {\n if (node.state.checked === 'mixed') {\n states.push('mixed');\n } else {\n states.push(node.state.checked ? 'checked' : 'unchecked');\n }\n }\n \n // Pressed state (toggle button)\n if (node.state.pressed !== undefined) {\n if (node.state.pressed === 'mixed') {\n states.push('mixed');\n } else {\n states.push(node.state.pressed ? 'pressed' : 'not pressed');\n }\n }\n \n // Selected state\n if (node.state.selected !== undefined) {\n states.push(node.state.selected ? 'selected' : 'unselected');\n }\n \n // Disabled state\n if (node.state.disabled) {\n states.push('dimmed');\n }\n \n // Invalid state\n if (node.state.invalid) {\n states.push('invalid data');\n }\n \n // Required state\n if (node.state.required) {\n states.push('required');\n }\n \n // Read-only state\n if (node.state.readonly) {\n states.push('read only');\n }\n \n // Busy state\n if (node.state.busy) {\n states.push('busy');\n }\n \n // Current state\n if (node.state.current) {\n if (node.state.current === 'page') {\n states.push('current page');\n } else if (node.state.current === 'step') {\n states.push('current step');\n } else if (node.state.current === 'location') {\n states.push('current location');\n } else if (node.state.current === 'date') {\n states.push('current date');\n } else if (node.state.current === 'time') {\n states.push('current time');\n } else if (node.state.current === 'true') {\n states.push('current');\n }\n }\n \n // Grabbed state (drag and drop)\n if (node.state.grabbed !== undefined) {\n states.push(node.state.grabbed ? 'grabbed' : 'not grabbed');\n }\n \n return states.join(', ');\n}\n","/**\n * Windows Narrator screen reader announcement renderer.\n * \n * Generates heuristic announcement text approximating Windows Narrator output.\n * This is NOT a perfect emulation - real Narrator behavior varies by version,\n * settings, and context. Use for development guidance only.\n */\n\nimport type { AccessibleNode, AccessibleRole, AnnouncementModel } from '../model/types.js';\nimport { createColors, type ColorFunctions } from '../cli/colors.js';\n\n/**\n * Renders an announcement model as Narrator-style announcement text.\n * \n * @param model - Announcement model to render\n * @param colorize - Whether to apply ANSI color codes to the output\n * @returns Narrator-style announcement text\n */\nexport function renderNarrator(model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const announcements: string[] = [];\n renderNodeNarrator(model.root, announcements, c);\n return announcements.join('\\n');\n}\n\n/**\n * Recursively renders a node and its children as Narrator announcements.\n * \n * @param node - Node to render\n * @param announcements - Array to collect announcement strings\n * @param c - Color functions for formatting\n */\nfunction renderNodeNarrator(node: AccessibleNode, announcements: string[], c: ColorFunctions): void {\n const announcement = formatNodeNarrator(node, c);\n if (announcement) {\n announcements.push(announcement);\n }\n\n // Recursively render children, collapsing redundant same-name children\n for (const child of node.children) {\n if (child.name && child.name === node.name && node.children.length === 1) {\n // Skip child that repeats parent name — recurse into grandchildren\n for (const grandchild of child.children) {\n renderNodeNarrator(grandchild, announcements, c);\n }\n continue;\n }\n renderNodeNarrator(child, announcements, c);\n }\n}\n\n/**\n * Formats a single node as a Narrator announcement.\n * \n * @param node - Node to format\n * @param c - Color functions for formatting\n * @returns Formatted announcement string or empty string if node should not be announced\n */\nfunction formatNodeNarrator(node: AccessibleNode, c: ColorFunctions): string {\n const parts: string[] = [];\n\n const roleFirst = shouldAnnounceRoleFirst(node.role);\n\n if (roleFirst) {\n // Role-first: role, name, state, value, description\n const roleText = formatRoleNarrator(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n } else {\n // Name-first: name, role, state, value, description\n if (node.name) {\n parts.push(c.elementName(node.name));\n }\n\n const roleText = formatRoleNarrator(node);\n if (roleText) {\n parts.push(c.roleName(roleText));\n }\n }\n\n // Add states\n const stateText = formatStatesNarrator(node);\n if (stateText) {\n parts.push(c.stateName(stateText));\n }\n\n // Add value (for form controls)\n if (node.value) {\n const valueText = node.value.text || String(node.value.current);\n if (valueText) {\n parts.push(valueText);\n }\n }\n\n // Add description (if present)\n if (node.description) {\n parts.push(c.description(node.description));\n }\n\n return parts.join(', ');\n}\n\n/**\n * Determines if role should be announced before name.\n * \n * Narrator announces role first for links, headings, landmarks,\n * and structural containers.\n * \n * @param role - Role to check\n * @returns true if role should be announced first\n */\nfunction shouldAnnounceRoleFirst(role: AccessibleRole): boolean {\n const roleFirstRoles: AccessibleRole[] = [\n 'link',\n 'heading',\n 'navigation',\n 'main',\n 'banner',\n 'contentinfo',\n 'complementary',\n 'region',\n 'form',\n 'search',\n 'blockquote',\n 'figure',\n 'dialog',\n 'group',\n 'document',\n ];\n return roleFirstRoles.includes(role);\n}\n\n/**\n * Formats the role portion of a Narrator announcement.\n * \n * @param node - Node to format\n * @returns Role text or empty string\n */\nfunction formatRoleNarrator(node: AccessibleNode): string {\n const role = node.role;\n\n switch (role) {\n case 'button':\n return 'button';\n\n case 'link':\n return 'link';\n\n case 'heading':\n if (node.state.level) {\n return `Heading level ${node.state.level}`;\n }\n return 'Heading';\n\n case 'textbox':\n return 'edit';\n\n case 'checkbox':\n return 'check box';\n\n case 'radio':\n return 'radio button';\n\n case 'combobox':\n return 'combo box';\n\n case 'listbox':\n return 'list box';\n\n case 'option':\n return 'option';\n\n case 'list':\n return 'list';\n\n case 'listitem':\n return 'list item';\n\n case 'navigation':\n return 'navigation';\n\n case 'main':\n return 'main';\n\n case 'banner':\n return 'banner';\n\n case 'contentinfo':\n return 'content info';\n\n case 'complementary':\n return 'complementary';\n\n case 'form':\n return 'form';\n\n case 'search':\n return 'search';\n\n case 'region':\n return 'region';\n\n case 'img':\n return 'image';\n\n case 'article':\n return 'article';\n\n case 'generic':\n return '';\n\n case 'staticText':\n case 'paragraph':\n case 'cell':\n case 'term':\n case 'definition':\n case 'caption':\n return '';\n\n case 'blockquote':\n return 'block quote';\n\n case 'code':\n return 'code';\n\n case 'table': {\n const rows = node.children.filter(c => c.role === 'row');\n const rowCount = rows.length;\n const colCount = rows.length > 0 ? rows[0].children.length : 0;\n return `table, ${rowCount} rows, ${colCount} columns`;\n }\n\n case 'row':\n return 'row';\n\n case 'columnheader':\n return 'column header';\n\n case 'rowheader':\n return 'row header';\n\n case 'figure':\n return 'figure';\n\n case 'dialog':\n return 'dialog';\n\n case 'meter':\n return 'meter';\n\n case 'progressbar':\n return 'progress bar';\n\n case 'status':\n return 'status';\n\n case 'group':\n return node.name ? 'group' : '';\n\n case 'document':\n return 'document';\n\n case 'application':\n return 'application';\n\n case 'separator':\n return 'separator';\n\n default:\n return role;\n }\n}\n\n/**\n * Formats the state portion of a Narrator announcement.\n * \n * @param node - Node to format\n * @returns State text or empty string\n */\nfunction formatStatesNarrator(node: AccessibleNode): string {\n const states: string[] = [];\n\n // Expanded/collapsed state\n if (node.state.expanded !== undefined) {\n states.push(node.state.expanded ? 'expanded' : 'collapsed');\n }\n\n // Checked state (checkbox/radio)\n if (node.state.checked !== undefined) {\n if (node.state.checked === 'mixed') {\n states.push('partially selected');\n } else {\n states.push(node.state.checked ? 'checked' : 'unchecked');\n }\n }\n\n // Pressed state (toggle button)\n if (node.state.pressed !== undefined) {\n if (node.state.pressed === 'mixed') {\n states.push('partially pressed');\n } else {\n states.push(node.state.pressed ? 'pressed' : 'not pressed');\n }\n }\n\n // Selected state\n if (node.state.selected !== undefined) {\n states.push(node.state.selected ? 'selected' : 'not selected');\n }\n\n // Disabled state\n if (node.state.disabled) {\n states.push('disabled');\n }\n\n // Invalid state\n if (node.state.invalid) {\n states.push('invalid');\n }\n\n // Required state\n if (node.state.required) {\n states.push('required');\n }\n\n // Read-only state\n if (node.state.readonly) {\n states.push('read only');\n }\n\n // Busy state\n if (node.state.busy) {\n states.push('busy');\n }\n\n // Current state\n if (node.state.current) {\n if (node.state.current === 'page') {\n states.push('current page');\n } else if (node.state.current === 'step') {\n states.push('current step');\n } else if (node.state.current === 'location') {\n states.push('current location');\n } else if (node.state.current === 'date') {\n states.push('current date');\n } else if (node.state.current === 'time') {\n states.push('current time');\n } else if (node.state.current === 'true') {\n states.push('current');\n }\n }\n\n // Grabbed state (drag and drop)\n if (node.state.grabbed !== undefined) {\n states.push(node.state.grabbed ? 'grabbed' : 'not grabbed');\n }\n\n return states.join(', ');\n}\n","/**\n * Developer-friendly audit report renderer.\n * \n * Generates human-readable accessibility audit reports with:\n * - Landmark structure analysis\n * - Heading hierarchy validation\n * - Interactive element inventory\n * - Common accessibility issue detection\n * - Summary statistics\n */\n\nimport type { AccessibleNode, AccessibleRole, AnnouncementModel } from '../model/types.js';\nimport { createColors } from '../cli/colors.js';\n\n/**\n * Severity level for accessibility issues.\n */\nexport type IssueSeverity = 'error' | 'warning' | 'info';\n\n/**\n * Accessibility issue detected during audit.\n */\nexport interface AccessibilityIssue {\n severity: IssueSeverity;\n message: string;\n suggestion?: string;\n element?: {\n role: AccessibleRole;\n name: string;\n };\n}\n\n/**\n * Audit report statistics.\n */\nexport interface AuditStatistics {\n totalElements: number;\n roleDistribution: Record<string, number>;\n landmarkCount: number;\n headingCount: number;\n interactiveCount: number;\n focusableCount: number;\n statesUsed: Set<string>;\n}\n\n/**\n * Complete audit report.\n */\nexport interface AuditReport {\n statistics: AuditStatistics;\n landmarks: AccessibleNode[];\n headings: AccessibleNode[];\n interactiveElements: AccessibleNode[];\n issues: AccessibilityIssue[];\n}\n\n/**\n * Renders an announcement model as a developer-friendly audit report.\n * \n * @param model - Announcement model to audit\n * @returns Formatted audit report text\n */\nexport function renderAuditReport(model: AnnouncementModel, colorize?: boolean): string {\n const report = generateAuditReport(model);\n return formatAuditReport(report, model, colorize);\n}\n\n/**\n * Generates audit report data from an announcement model.\n * \n * @param model - Announcement model to analyze\n * @returns Audit report data\n */\nexport function generateAuditReport(model: AnnouncementModel): AuditReport {\n const statistics: AuditStatistics = {\n totalElements: 0,\n roleDistribution: {},\n landmarkCount: 0,\n headingCount: 0,\n interactiveCount: 0,\n focusableCount: 0,\n statesUsed: new Set(),\n };\n \n const landmarks: AccessibleNode[] = [];\n const headings: AccessibleNode[] = [];\n const interactiveElements: AccessibleNode[] = [];\n const issues: AccessibilityIssue[] = [];\n \n // Collect data from tree\n collectAuditData(model.root, statistics, landmarks, headings, interactiveElements);\n \n // Detect issues\n detectLandmarkIssues(landmarks, issues);\n detectHeadingIssues(headings, issues);\n detectInteractiveIssues(interactiveElements, issues);\n \n return {\n statistics,\n landmarks,\n headings,\n interactiveElements,\n issues,\n };\n}\n\n/**\n * Recursively collects audit data from the accessibility tree.\n */\nfunction collectAuditData(\n node: AccessibleNode,\n statistics: AuditStatistics,\n landmarks: AccessibleNode[],\n headings: AccessibleNode[],\n interactiveElements: AccessibleNode[]\n): void {\n // Skip generic containers in statistics\n if (node.role !== 'generic') {\n statistics.totalElements++;\n \n // Update role distribution\n statistics.roleDistribution[node.role] = (statistics.roleDistribution[node.role] || 0) + 1;\n \n // Collect landmarks\n if (isLandmark(node.role)) {\n statistics.landmarkCount++;\n landmarks.push(node);\n }\n \n // Collect headings\n if (node.role === 'heading') {\n statistics.headingCount++;\n headings.push(node);\n }\n \n // Collect interactive elements\n if (isInteractive(node.role)) {\n statistics.interactiveCount++;\n interactiveElements.push(node);\n }\n \n // Count focusable elements\n if (node.focus.focusable) {\n statistics.focusableCount++;\n }\n \n // Collect states used\n Object.keys(node.state).forEach(state => {\n if (node.state[state as keyof typeof node.state] !== undefined) {\n statistics.statesUsed.add(state);\n }\n });\n }\n \n // Recurse through children\n for (const child of node.children) {\n collectAuditData(child, statistics, landmarks, headings, interactiveElements);\n }\n}\n\n/**\n * Checks if a role is a landmark.\n */\nfunction isLandmark(role: AccessibleRole): boolean {\n return [\n 'navigation',\n 'main',\n 'banner',\n 'contentinfo',\n 'region',\n 'complementary',\n 'form',\n 'search',\n ].includes(role);\n}\n\n/**\n * Checks if a role is interactive.\n */\nfunction isInteractive(role: AccessibleRole): boolean {\n return [\n 'button',\n 'link',\n 'textbox',\n 'checkbox',\n 'radio',\n 'combobox',\n 'listbox',\n 'option',\n ].includes(role);\n}\n\n/**\n * Detects issues with landmarks.\n */\nfunction detectLandmarkIssues(landmarks: AccessibleNode[], issues: AccessibilityIssue[]): void {\n if (landmarks.length === 0) {\n issues.push({\n severity: 'info',\n message: 'No landmarks found',\n suggestion: 'Consider adding semantic landmarks (main, nav, aside, etc.)',\n });\n }\n \n // Check for unnamed landmarks\n landmarks.forEach(landmark => {\n if (!landmark.name && ['navigation', 'region', 'complementary', 'form'].includes(landmark.role)) {\n issues.push({\n severity: 'warning',\n message: `${landmark.role} landmark has no accessible name`,\n suggestion: `Add aria-label=\"${landmark.role === 'navigation' ? 'Main navigation' : 'Descriptive name'}\" to the ${landmark.role} element`,\n element: {\n role: landmark.role,\n name: landmark.name,\n },\n });\n }\n });\n \n // Check for duplicate landmark roles without distinguishing names\n const landmarksByRole = new Map<string, AccessibleNode[]>();\n landmarks.forEach(landmark => {\n if (!landmarksByRole.has(landmark.role)) {\n landmarksByRole.set(landmark.role, []);\n }\n landmarksByRole.get(landmark.role)!.push(landmark);\n });\n \n landmarksByRole.forEach((nodes, role) => {\n if (nodes.length > 1) {\n const allUnnamed = nodes.every(n => !n.name);\n const allSameName = nodes.every(n => n.name === nodes[0].name);\n \n if (allUnnamed || allSameName) {\n issues.push({\n severity: 'warning',\n message: `Multiple ${role} landmarks without distinguishing names`,\n suggestion: `Add unique aria-label attributes to distinguish between ${role} landmarks`,\n });\n }\n }\n });\n}\n\n/**\n * Detects issues with heading hierarchy.\n */\nfunction detectHeadingIssues(headings: AccessibleNode[], issues: AccessibilityIssue[]): void {\n if (headings.length === 0) {\n return;\n }\n \n // Check if first heading is h1\n const firstHeading = headings[0];\n if (firstHeading.state.level && firstHeading.state.level !== 1) {\n issues.push({\n severity: 'error',\n message: `First heading is h${firstHeading.state.level} (should be h1)`,\n suggestion: `Change <h${firstHeading.state.level}> to <h1> or add h1 before it`,\n element: {\n role: firstHeading.role,\n name: firstHeading.name,\n },\n });\n }\n \n // Check for skipped levels\n for (let i = 1; i < headings.length; i++) {\n const prevLevel = headings[i - 1].state.level || 1;\n const currLevel = headings[i].state.level || 1;\n \n if (currLevel > prevLevel + 1) {\n issues.push({\n severity: 'error',\n message: `Heading hierarchy violation: h${prevLevel} followed by h${currLevel} (skipped h${prevLevel + 1})`,\n suggestion: `Change h${currLevel} to h${prevLevel + 1} or add intermediate heading levels`,\n element: {\n role: headings[i].role,\n name: headings[i].name,\n },\n });\n }\n }\n}\n\n/**\n * Detects issues with interactive elements.\n */\nfunction detectInteractiveIssues(elements: AccessibleNode[], issues: AccessibilityIssue[]): void {\n elements.forEach(element => {\n // Check for missing names\n if (!element.name) {\n issues.push({\n severity: 'error',\n message: `${element.role} has no accessible name`,\n suggestion: element.role === 'button' \n ? 'Add text content or aria-label to button'\n : element.role === 'link'\n ? 'Add text content or aria-label to link'\n : `Add aria-label to ${element.role}`,\n element: {\n role: element.role,\n name: element.name,\n },\n });\n }\n \n // Check for form inputs without labels\n if (element.role === 'textbox' && !element.name) {\n issues.push({\n severity: 'error',\n message: 'Input has no associated label',\n suggestion: 'Add <label> element or aria-label attribute',\n element: {\n role: element.role,\n name: element.name,\n },\n });\n }\n });\n}\n\n/**\n * Formats audit report as human-readable text.\n */\nfunction formatAuditReport(report: AuditReport, model: AnnouncementModel, colorize?: boolean): string {\n const c = createColors(colorize ?? false);\n const lines: string[] = [];\n \n // Header\n lines.push(c.title('╔══════════════════════════════════════════════════════════════════════════════╗'));\n lines.push(c.title('║ ACCESSIBILITY AUDIT REPORT ║'));\n lines.push(c.title('╚══════════════════════════════════════════════════════════════════════════════╝'));\n lines.push('');\n lines.push(c.dim(`Analyzed: ${model.metadata.extractedAt}`));\n lines.push('');\n \n // Landmark structure\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('📍 LANDMARK STRUCTURE'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n if (report.landmarks.length === 0) {\n lines.push(c.error('✗ No landmarks found'));\n } else {\n lines.push(c.success(`✓ ${report.landmarks.length} landmark(s) found`));\n lines.push('');\n report.landmarks.forEach(landmark => {\n const name = landmark.name ? `\"${landmark.name}\"` : '(unnamed)';\n lines.push(`${landmark.role} ${name}`);\n });\n }\n lines.push('');\n \n // Heading hierarchy\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('📑 HEADING HIERARCHY'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n if (report.headings.length === 0) {\n lines.push(c.info('ℹ No headings found'));\n } else {\n const hasHierarchyIssues = report.issues.some(i => \n i.message.includes('heading') || i.message.includes('h1') || i.message.includes('h2')\n );\n lines.push(`${hasHierarchyIssues ? c.error('✗') : c.success('✓')} ${report.headings.length} heading(s) found ${hasHierarchyIssues ? '(HIERARCHY VIOLATION)' : '(proper hierarchy)'}`);\n lines.push('');\n \n report.headings.forEach(heading => {\n const level = heading.state.level || 1;\n const indent = ' '.repeat(level - 1);\n lines.push(`${indent}h${level} \"${heading.name}\"`);\n });\n }\n lines.push('');\n \n // Interactive elements\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('🎯 INTERACTIVE ELEMENTS'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n if (report.interactiveElements.length === 0) {\n lines.push(c.info('ℹ No interactive elements found'));\n } else {\n lines.push(c.success(`✓ ${report.interactiveElements.length} interactive element(s) found`));\n lines.push('');\n \n // Group by role\n const byRole = new Map<string, AccessibleNode[]>();\n report.interactiveElements.forEach(el => {\n if (!byRole.has(el.role)) {\n byRole.set(el.role, []);\n }\n byRole.get(el.role)!.push(el);\n });\n \n byRole.forEach((elements, role) => {\n lines.push(`${role}s (${elements.length}):`);\n elements.forEach(el => {\n const name = el.name ? `\"${el.name}\"` : '(unnamed)';\n const states = Object.keys(el.state).filter(k => el.state[k as keyof typeof el.state] !== undefined);\n const stateStr = states.length > 0 ? ` [${states.join(', ')}]` : '';\n lines.push(` • ${name}${stateStr}`);\n });\n });\n }\n lines.push('');\n \n // Summary statistics\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('📊 SUMMARY STATISTICS'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n lines.push(`Total accessible elements: ${report.statistics.totalElements}`);\n lines.push('');\n lines.push('Role distribution:');\n Object.entries(report.statistics.roleDistribution)\n .sort((a, b) => b[1] - a[1])\n .forEach(([role, count]) => {\n lines.push(c.dim(` • ${role}: ${count}`));\n });\n lines.push('');\n lines.push(c.dim(`Focusable elements: ${report.statistics.focusableCount}`));\n lines.push('');\n \n // Issues\n if (report.issues.length > 0) {\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.heading('⚠️ ACCESSIBILITY ISSUES'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n const errors = report.issues.filter(i => i.severity === 'error');\n const warnings = report.issues.filter(i => i.severity === 'warning');\n const infos = report.issues.filter(i => i.severity === 'info');\n \n if (errors.length > 0) {\n lines.push(c.error(`✗ Error (${errors.length}):`));\n errors.forEach(issue => {\n lines.push(c.error(` • ${issue.message}`));\n if (issue.suggestion) {\n lines.push(` → ${issue.suggestion}`);\n }\n });\n lines.push('');\n }\n \n if (warnings.length > 0) {\n lines.push(c.warning(`⚠ Warning (${warnings.length}):`));\n warnings.forEach(issue => {\n lines.push(c.warning(` • ${issue.message}`));\n if (issue.suggestion) {\n lines.push(` → ${issue.suggestion}`);\n }\n });\n lines.push('');\n }\n \n if (infos.length > 0) {\n lines.push(c.info(`ℹ Info (${infos.length}):`));\n infos.forEach(issue => {\n lines.push(c.info(` • ${issue.message}`));\n if (issue.suggestion) {\n lines.push(` → ${issue.suggestion}`);\n }\n });\n lines.push('');\n }\n }\n \n // Overall assessment\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push(c.success('✅ OVERALL ASSESSMENT'));\n lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\n lines.push('');\n \n const errorCount = report.issues.filter(i => i.severity === 'error').length;\n const warningCount = report.issues.filter(i => i.severity === 'warning').length;\n \n if (errorCount === 0 && warningCount === 0) {\n lines.push(c.success('Excellent! No critical issues found.'));\n } else if (errorCount > 0) {\n lines.push(`Critical accessibility issues found:`);\n lines.push(c.error(` ✗ ${errorCount} error(s)`));\n if (warningCount > 0) {\n lines.push(c.warning(` ⚠ ${warningCount} warning(s)`));\n }\n lines.push('');\n lines.push('Recommendation: Address errors before deployment');\n } else {\n lines.push(`Good structure with minor improvements needed:`);\n lines.push(c.warning(` ⚠ ${warningCount} warning(s)`));\n }\n \n return lines.join('\\n');\n}\n","/**\n * HTML parsing using jsdom.\n * \n * Provides lenient parsing with error recovery for malformed HTML.\n */\n\nimport { JSDOM } from 'jsdom';\n\n/**\n * Parsing error class.\n */\nexport class ParsingError extends Error {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = 'ParsingError';\n }\n}\n\n/**\n * Parsing warning.\n */\nexport interface ParsingWarning {\n message: string;\n line?: number;\n column?: number;\n}\n\n/**\n * Result of HTML parsing.\n */\nexport interface ParseResult {\n /** Parsed DOM document */\n document: Document;\n \n /** Warnings encountered during parsing */\n warnings: ParsingWarning[];\n}\n\n/**\n * Maximum input size in bytes (10 MB).\n * Prevents denial-of-service from extremely large inputs.\n */\nconst MAX_INPUT_SIZE = 10 * 1024 * 1024;\n\n/**\n * Parses HTML string into a DOM document.\n * \n * Uses jsdom with lenient parsing mode to handle malformed HTML.\n * Emits warnings for issues but continues processing.\n * \n * @param html - HTML string to parse\n * @returns Parse result with document and warnings\n * @throws ParsingError if parsing fails completely or input exceeds size limit\n */\nexport function parseHTML(html: string): ParseResult {\n const warnings: ParsingWarning[] = [];\n\n // Input size validation\n const inputSize = Buffer.byteLength(html, 'utf-8');\n if (inputSize > MAX_INPUT_SIZE) {\n throw new ParsingError(\n `Input exceeds maximum size of ${MAX_INPUT_SIZE / (1024 * 1024)} MB (received ${(inputSize / (1024 * 1024)).toFixed(1)} MB). ` +\n `Use CSS selectors to analyze specific sections of large documents.`\n );\n }\n\n try {\n // Create JSDOM instance with lenient parsing\n const dom = new JSDOM(html, {\n contentType: 'text/html',\n // Include useful defaults for accessibility tree extraction\n includeNodeLocations: false,\n storageQuota: 0,\n });\n\n const document = dom.window.document;\n\n // Check for parsing errors in the document\n // jsdom doesn't expose parse errors directly, but we can check for common issues\n if (!document.documentElement) {\n warnings.push({\n message: 'Document has no root element. HTML may be severely malformed.',\n });\n }\n\n // Check if body exists (should be created even for empty HTML)\n if (!document.body) {\n warnings.push({\n message: 'Document has no body element. HTML may be malformed.',\n });\n }\n\n return {\n document,\n warnings,\n };\n } catch (error) {\n // jsdom parsing failed completely\n throw new ParsingError(\n `Failed to parse HTML: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Parses HTML and returns just the document (throws on warnings).\n * \n * Convenience function for cases where warnings should be treated as errors.\n * \n * @param html - HTML string to parse\n * @returns Parsed DOM document\n * @throws ParsingError if parsing fails or warnings are present\n */\nexport function parseHTMLStrict(html: string): Document {\n const result = parseHTML(html);\n\n if (result.warnings.length > 0) {\n const warningMessages = result.warnings.map((w) => w.message).join('; ');\n throw new ParsingError(`HTML parsing warnings: ${warningMessages}`);\n }\n\n return result.document;\n}\n\n/**\n * Validates that HTML string is not empty.\n * \n * @param html - HTML string to validate\n * @throws ParsingError if HTML is empty or whitespace-only\n */\nexport function validateHTMLNotEmpty(html: string): void {\n if (!html || html.trim().length === 0) {\n throw new ParsingError('HTML input is empty or contains only whitespace');\n }\n}\n","/**\n * ARIA accessible name computation.\n * \n * Implements the ARIA name computation algorithm following the W3C specification.\n * https://www.w3.org/TR/accname-1.2/\n */\n\n/**\n * Warning emitted during name computation.\n */\nexport interface NameComputationWarning {\n message: string;\n element: Element;\n}\n\n/**\n * Result of name computation.\n */\nexport interface NameComputationResult {\n name: string;\n warnings: NameComputationWarning[];\n}\n\n/**\n * Result of description computation.\n */\nexport interface DescriptionComputationResult {\n description: string;\n warnings: NameComputationWarning[];\n}\n\n/**\n * Computes the accessible name for an element following ARIA specification.\n * \n * Priority order:\n * 1. aria-labelledby (references to other elements)\n * 2. aria-label\n * 3. Native label (for form controls)\n * 4. alt attribute (for images)\n * 5. Text content (for elements that support it)\n * 6. title attribute (fallback)\n * \n * @param element - Element to compute name for\n * @param visited - Set of visited elements (for cycle detection)\n * @returns Computed accessible name and warnings\n */\nexport function computeAccessibleName(\n element: Element,\n visited: Set<Element> = new Set()\n): NameComputationResult {\n const warnings: NameComputationWarning[] = [];\n\n // Detect circular references\n if (visited.has(element)) {\n warnings.push({\n message: 'Circular reference detected in aria-labelledby chain',\n element,\n });\n return { name: '', warnings };\n }\n\n visited.add(element);\n\n // 1. aria-labelledby (highest priority)\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy) {\n const name = computeNameFromLabelledBy(element, labelledBy, visited, warnings);\n // Always return if aria-labelledby is present, even if name is empty\n return { name, warnings };\n }\n\n // 2. aria-label\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return { name: ariaLabel.trim(), warnings };\n }\n\n // 3. Native label (for form controls)\n if (isFormControl(element)) {\n const labelName = computeNameFromLabel(element);\n if (labelName) {\n return { name: labelName, warnings };\n }\n }\n\n // 4. alt attribute (for images)\n if (element.tagName.toLowerCase() === 'img') {\n const alt = element.getAttribute('alt');\n if (alt !== null) {\n return { name: alt.trim(), warnings };\n }\n }\n\n // 5. Text content (for elements that support it)\n if (supportsNameFromContent(element)) {\n const textName = computeNameFromContent(element, visited);\n if (textName) {\n return { name: textName, warnings };\n }\n }\n\n // 6. title attribute (fallback)\n const title = element.getAttribute('title');\n if (title && title.trim()) {\n return { name: title.trim(), warnings };\n }\n\n // No name found\n return { name: '', warnings };\n}\n\n/**\n * Computes name from aria-labelledby attribute.\n * \n * @param element - Element with aria-labelledby\n * @param labelledBy - Space-separated list of IDs\n * @param visited - Set of visited elements\n * @param warnings - Array to collect warnings\n * @returns Computed name or empty string\n */\nfunction computeNameFromLabelledBy(\n element: Element,\n labelledBy: string,\n visited: Set<Element>,\n warnings: NameComputationWarning[]\n): string {\n const document = element.ownerDocument;\n if (!document) {\n return '';\n }\n\n const ids = labelledBy.trim().split(/\\s+/);\n const names: string[] = [];\n\n for (const id of ids) {\n if (!id) continue;\n\n const referencedElement = document.getElementById(id);\n if (!referencedElement) {\n warnings.push({\n message: `aria-labelledby references non-existent ID: ${id}`,\n element,\n });\n continue;\n }\n\n // Recursively compute name for referenced element\n // For labelledby, we want the text content of the referenced element\n const result = computeAccessibleName(referencedElement, new Set(visited));\n warnings.push(...result.warnings);\n \n // If no name was computed, fall back to text content\n const name = result.name || getTextContent(referencedElement);\n if (name) {\n names.push(name);\n }\n }\n\n return names.join(' ').trim();\n}\n\n/**\n * Computes name from associated label element.\n * \n * @param element - Form control element\n * @returns Name from label or empty string\n */\nfunction computeNameFromLabel(element: Element): string {\n const document = element.ownerDocument;\n if (!document) {\n return '';\n }\n\n // Check for explicit label association via id\n const id = element.getAttribute('id');\n if (id) {\n const label = document.querySelector(`label[for=\"${id}\"]`);\n if (label) {\n return getTextContent(label);\n }\n }\n\n // Check for implicit label (element inside label)\n const parentLabel = element.closest('label');\n if (parentLabel) {\n return getTextContent(parentLabel);\n }\n\n return '';\n}\n\n/**\n * Computes name from element's text content.\n * \n * @param element - Element to get text from\n * @param visited - Set of visited elements\n * @returns Text content or empty string\n */\nfunction computeNameFromContent(element: Element, _visited: Set<Element>): string {\n return getTextContent(element);\n}\n\n/**\n * Gets text content from an element, excluding hidden elements.\n * \n * @param element - Element to get text from\n * @returns Trimmed text content\n */\nfunction getTextContent(element: Element): string {\n // Skip hidden elements\n if (element.getAttribute('aria-hidden') === 'true') {\n return '';\n }\n\n let text = '';\n\n for (const node of Array.from(element.childNodes)) {\n if (node.nodeType === 3) { // TEXT_NODE\n text += node.textContent || '';\n } else if (node.nodeType === 1) { // ELEMENT_NODE\n const childElement = node as Element;\n \n // Skip hidden children\n if (childElement.getAttribute('aria-hidden') === 'true') {\n continue;\n }\n\n text += getTextContent(childElement);\n }\n }\n\n return text.trim();\n}\n\n/**\n * Checks if element is a form control.\n * \n * @param element - Element to check\n * @returns true if element is a form control\n */\nfunction isFormControl(element: Element): boolean {\n const tagName = element.tagName.toLowerCase();\n return (\n tagName === 'input' ||\n tagName === 'textarea' ||\n tagName === 'select' ||\n tagName === 'button'\n );\n}\n\n/**\n * Checks if element supports name from content.\n * \n * Elements like buttons, links, and headings get their name from text content.\n * Form inputs do not.\n * \n * @param element - Element to check\n * @returns true if element supports name from content\n */\nfunction supportsNameFromContent(element: Element): boolean {\n const tagName = element.tagName.toLowerCase();\n const role = element.getAttribute('role');\n\n // Elements that support name from content\n const contentElements = [\n 'button',\n 'a',\n 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'summary',\n 'figcaption',\n 'legend',\n 'caption',\n 'th',\n 'td',\n 'li',\n 'dt',\n 'dd',\n ];\n\n if (contentElements.includes(tagName)) {\n return true;\n }\n\n // Roles that support name from content\n const contentRoles = [\n 'button',\n 'link',\n 'heading',\n 'tab',\n 'treeitem',\n 'option',\n 'row',\n 'cell',\n 'columnheader',\n 'rowheader',\n 'tooltip',\n 'menuitem',\n 'menuitemcheckbox',\n 'menuitemradio',\n ];\n\n if (role && contentRoles.includes(role)) {\n return true;\n }\n\n return false;\n}\n\n\n/**\n * Computes the accessible description for an element.\n * \n * Priority order:\n * 1. aria-describedby (references to other elements)\n * 2. title attribute (fallback)\n * \n * @param element - Element to compute description for\n * @returns Computed accessible description and warnings\n */\nexport function computeAccessibleDescription(\n element: Element\n): DescriptionComputationResult {\n const warnings: NameComputationWarning[] = [];\n\n // 1. aria-describedby (highest priority)\n const describedBy = element.getAttribute('aria-describedby');\n if (describedBy) {\n const description = computeDescriptionFromDescribedBy(\n element,\n describedBy,\n warnings\n );\n if (description) {\n return { description, warnings };\n }\n }\n\n // 2. title attribute (fallback)\n const title = element.getAttribute('title');\n if (title && title.trim()) {\n return { description: title.trim(), warnings };\n }\n\n // No description found\n return { description: '', warnings };\n}\n\n/**\n * Computes description from aria-describedby attribute.\n * \n * @param element - Element with aria-describedby\n * @param describedBy - Space-separated list of IDs\n * @param warnings - Array to collect warnings\n * @returns Computed description or empty string\n */\nfunction computeDescriptionFromDescribedBy(\n element: Element,\n describedBy: string,\n warnings: NameComputationWarning[]\n): string {\n const document = element.ownerDocument;\n if (!document) {\n return '';\n }\n\n const ids = describedBy.trim().split(/\\s+/);\n const descriptions: string[] = [];\n\n for (const id of ids) {\n if (!id) continue;\n\n const referencedElement = document.getElementById(id);\n if (!referencedElement) {\n warnings.push({\n message: `aria-describedby references non-existent ID: ${id}`,\n element,\n });\n continue;\n }\n\n // Get text content from referenced element\n const text = getTextContent(referencedElement);\n if (text) {\n descriptions.push(text);\n }\n }\n\n return descriptions.join(' ').trim();\n}\n","/**\n * Role computation and mapping.\n * \n * Maps HTML elements to their implicit ARIA roles and validates explicit roles.\n */\n\nimport type { AccessibleRole } from '../model/types.js';\nimport { SUPPORTED_ROLES } from '../model/types.js';\n\n/**\n * Warning emitted during role computation.\n */\nexport interface RoleComputationWarning {\n message: string;\n element: Element;\n}\n\n/**\n * Result of role computation.\n */\nexport interface RoleComputationResult {\n role: AccessibleRole | null;\n warnings: RoleComputationWarning[];\n}\n\n/**\n * Mapping of HTML elements to their implicit ARIA roles.\n */\nconst IMPLICIT_ROLE_MAP: Record<string, AccessibleRole> = {\n // Interactive elements\n 'button': 'button',\n 'a': 'link', // Only if href attribute present\n \n // Form controls\n 'input': 'textbox', // Default, varies by type\n 'textarea': 'textbox',\n 'select': 'listbox',\n \n // Headings\n 'h1': 'heading',\n 'h2': 'heading',\n 'h3': 'heading',\n 'h4': 'heading',\n 'h5': 'heading',\n 'h6': 'heading',\n \n // Landmarks\n 'nav': 'navigation',\n 'main': 'main',\n 'header': 'banner', // Only if not nested in article/section\n 'footer': 'contentinfo', // Only if not nested in article/section\n 'aside': 'complementary',\n 'form': 'form',\n 'section': 'region', // Only if has accessible name\n \n // Lists\n 'ul': 'list',\n 'ol': 'list',\n 'li': 'listitem',\n \n // Images\n 'img': 'img',\n \n // Articles\n 'article': 'article',\n\n // Static content (new)\n 'p': 'paragraph',\n 'blockquote': 'blockquote',\n 'code': 'code',\n 'pre': 'code',\n\n // Tables (new)\n 'table': 'table',\n 'tr': 'row',\n 'td': 'cell',\n 'th': 'columnheader', // Default; scope=\"row\" handled in computeImplicitRole\n\n // Definition lists (new)\n 'dl': 'list',\n 'dt': 'term',\n 'dd': 'definition',\n\n // Figures (new)\n 'figure': 'figure',\n 'figcaption': 'caption',\n\n // Disclosure (new)\n 'details': 'group',\n 'summary': 'button',\n\n // Dialogs and widgets (new)\n 'dialog': 'dialog',\n 'meter': 'meter',\n 'progress': 'progressbar',\n 'output': 'status',\n\n // Forms (new)\n 'fieldset': 'group',\n 'legend': 'caption',\n\n // Embedded content (new)\n 'iframe': 'document',\n 'video': 'application',\n 'audio': 'application',\n\n // Separators (new)\n 'hr': 'separator',\n\n // Table caption (new)\n 'caption': 'caption',\n};\n\n/**\n * Input type to role mapping.\n */\nconst INPUT_TYPE_ROLE_MAP: Record<string, AccessibleRole> = {\n 'button': 'button',\n 'submit': 'button',\n 'reset': 'button',\n 'checkbox': 'checkbox',\n 'radio': 'radio',\n 'text': 'textbox',\n 'email': 'textbox',\n 'password': 'textbox',\n 'search': 'textbox',\n 'tel': 'textbox',\n 'url': 'textbox',\n 'number': 'textbox',\n};\n\n/**\n * Computes the accessible role for an element.\n * \n * Priority:\n * 1. Explicit role attribute (if valid)\n * 2. Implicit role based on element type\n * 3. null if no role\n * \n * @param element - Element to compute role for\n * @returns Computed role and warnings\n */\nexport function computeRole(element: Element): RoleComputationResult {\n const warnings: RoleComputationWarning[] = [];\n \n // 1. Check for explicit role attribute\n const explicitRole = element.getAttribute('role');\n if (explicitRole) {\n const role = validateAndNormalizeRole(explicitRole, element, warnings);\n if (role) {\n return { role, warnings };\n }\n // If explicit role is invalid, fall through to implicit role\n }\n \n // 2. Compute implicit role\n const implicitRole = computeImplicitRole(element, warnings);\n return { role: implicitRole, warnings };\n}\n\n/**\n * Validates and normalizes an explicit role attribute.\n * \n * @param roleAttr - Role attribute value\n * @param element - Element with the role\n * @param warnings - Array to collect warnings\n * @returns Validated role or null if invalid\n */\nfunction validateAndNormalizeRole(\n roleAttr: string,\n element: Element,\n warnings: RoleComputationWarning[]\n): AccessibleRole | null {\n const role = roleAttr.trim().toLowerCase();\n \n // Check for presentation/none roles (elements should be hidden from a11y tree)\n if (role === 'presentation' || role === 'none') {\n return null;\n }\n \n // Validate against supported roles\n if (SUPPORTED_ROLES.includes(role as AccessibleRole)) {\n return role as AccessibleRole;\n }\n \n // Invalid or unsupported role\n warnings.push({\n message: `Invalid or unsupported role: \"${roleAttr}\". Falling back to implicit role.`,\n element,\n });\n \n return null;\n}\n\n/**\n * Computes the implicit ARIA role for an element.\n * \n * @param element - Element to compute implicit role for\n * @param warnings - Array to collect warnings\n * @returns Implicit role or null\n */\nfunction computeImplicitRole(\n element: Element,\n _warnings: RoleComputationWarning[]\n): AccessibleRole | null {\n const tagName = element.tagName.toLowerCase();\n \n // Special case: input elements vary by type\n if (tagName === 'input') {\n return computeInputRole(element as HTMLInputElement);\n }\n \n // Special case: links only have link role if href present\n if (tagName === 'a') {\n return element.hasAttribute('href') ? 'link' : null;\n }\n \n // Special case: header/footer only landmarks if not nested\n if (tagName === 'header') {\n return isTopLevelLandmark(element) ? 'banner' : null;\n }\n \n if (tagName === 'footer') {\n return isTopLevelLandmark(element) ? 'contentinfo' : null;\n }\n \n // Special case: th elements — scope=\"row\" maps to rowheader\n if (tagName === 'th') {\n const scope = element.getAttribute('scope');\n return scope === 'row' ? 'rowheader' : 'columnheader';\n }\n\n // Special case: section only has region role if it has accessible name\n if (tagName === 'section') {\n // For now, we'll return 'region' - the caller should check if it has a name\n // In a full implementation, we'd check for aria-label or aria-labelledby\n return element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby')\n ? 'region'\n : null;\n }\n \n // Look up in implicit role map\n const implicitRole = IMPLICIT_ROLE_MAP[tagName];\n return implicitRole || null;\n}\n\n/**\n * Computes the role for an input element based on its type.\n * \n * @param input - Input element\n * @returns Role for the input\n */\nfunction computeInputRole(input: HTMLInputElement): AccessibleRole {\n const type = (input.getAttribute('type') || 'text').toLowerCase();\n return INPUT_TYPE_ROLE_MAP[type] || 'textbox';\n}\n\n/**\n * Checks if header/footer is a top-level landmark.\n * \n * Header and footer only have landmark roles (banner/contentinfo) when they\n * are not nested inside article or section elements.\n * \n * @param element - Header or footer element\n * @returns true if top-level landmark\n */\nfunction isTopLevelLandmark(element: Element): boolean {\n let parent = element.parentElement;\n \n while (parent) {\n const tagName = parent.tagName.toLowerCase();\n if (tagName === 'article' || tagName === 'section') {\n return false;\n }\n parent = parent.parentElement;\n }\n \n return true;\n}\n\n/**\n * Checks if an element should be included in the accessibility tree.\n * \n * Elements are excluded if:\n * - They have role=\"presentation\" or role=\"none\"\n * - They have aria-hidden=\"true\"\n * - They have no accessible role\n * \n * @param element - Element to check\n * @returns true if element should be included\n */\nexport function isAccessible(element: Element): boolean {\n // Check aria-hidden\n if (element.getAttribute('aria-hidden') === 'true') {\n return false;\n }\n \n // Check for presentation/none role\n const role = element.getAttribute('role');\n if (role === 'presentation' || role === 'none') {\n return false;\n }\n \n // Element is accessible if it has a role (explicit or implicit)\n const roleResult = computeRole(element);\n return roleResult.role !== null;\n}\n","/**\n * State and property extraction from ARIA attributes.\n * \n * Extracts accessibility states and properties from elements.\n */\n\nimport type { AccessibleState, AccessibleValue } from '../model/types.js';\n\n/**\n * Warning emitted during state extraction.\n */\nexport interface StateExtractionWarning {\n message: string;\n element: Element;\n}\n\n/**\n * Result of state extraction.\n */\nexport interface StateExtractionResult {\n state: AccessibleState;\n warnings: StateExtractionWarning[];\n}\n\n/**\n * Result of value extraction.\n */\nexport interface ValueExtractionResult {\n value: AccessibleValue | undefined;\n warnings: StateExtractionWarning[];\n}\n\n/**\n * Extracts accessibility state from an element.\n * \n * Extracts ARIA state attributes and native element states.\n * \n * @param element - Element to extract state from\n * @returns Extracted state and warnings\n */\nexport function extractState(element: Element): StateExtractionResult {\n const warnings: StateExtractionWarning[] = [];\n const state: AccessibleState = {};\n\n // aria-expanded\n const expanded = extractBooleanAttribute(element, 'aria-expanded', warnings);\n if (expanded !== undefined) {\n state.expanded = expanded;\n }\n\n // aria-checked (boolean or 'mixed')\n const checked = extractTriStateAttribute(element, 'aria-checked', warnings);\n if (checked !== undefined) {\n state.checked = checked;\n }\n\n // aria-pressed (boolean or 'mixed')\n const pressed = extractTriStateAttribute(element, 'aria-pressed', warnings);\n if (pressed !== undefined) {\n state.pressed = pressed;\n }\n\n // aria-selected\n const selected = extractBooleanAttribute(element, 'aria-selected', warnings);\n if (selected !== undefined) {\n state.selected = selected;\n }\n\n // aria-disabled\n const disabled = extractBooleanAttribute(element, 'aria-disabled', warnings);\n if (disabled !== undefined) {\n state.disabled = disabled;\n }\n\n // aria-invalid\n const invalid = extractBooleanAttribute(element, 'aria-invalid', warnings);\n if (invalid !== undefined) {\n state.invalid = invalid;\n }\n\n // aria-required\n const required = extractBooleanAttribute(element, 'aria-required', warnings);\n if (required !== undefined) {\n state.required = required;\n }\n\n // aria-readonly\n const readonly = extractBooleanAttribute(element, 'aria-readonly', warnings);\n if (readonly !== undefined) {\n state.readonly = readonly;\n }\n\n // aria-busy\n const busy = extractBooleanAttribute(element, 'aria-busy', warnings);\n if (busy !== undefined) {\n state.busy = busy;\n }\n\n // aria-current\n const current = extractCurrentAttribute(element, warnings);\n if (current !== undefined) {\n state.current = current;\n }\n\n // aria-grabbed\n const grabbed = extractBooleanAttribute(element, 'aria-grabbed', warnings);\n if (grabbed !== undefined) {\n state.grabbed = grabbed;\n }\n\n // aria-hidden\n const hidden = extractBooleanAttribute(element, 'aria-hidden', warnings);\n if (hidden !== undefined) {\n state.hidden = hidden;\n }\n\n // aria-level (for headings)\n const level = extractLevelAttribute(element, warnings);\n if (level !== undefined) {\n state.level = level;\n }\n\n // aria-posinset and aria-setsize (for lists, tabs, etc.)\n const posinset = extractNumberAttribute(element, 'aria-posinset', warnings);\n if (posinset !== undefined) {\n state.posinset = posinset;\n }\n\n const setsize = extractNumberAttribute(element, 'aria-setsize', warnings);\n if (setsize !== undefined) {\n state.setsize = setsize;\n }\n\n // Extract native element states\n extractNativeStates(element, state, warnings);\n\n return { state, warnings };\n}\n\n/**\n * Extracts value information from form controls.\n * \n * @param element - Element to extract value from\n * @returns Extracted value and warnings\n */\nexport function extractValue(element: Element): ValueExtractionResult {\n const warnings: StateExtractionWarning[] = [];\n\n // Only extract value for form controls\n const tagName = element.tagName.toLowerCase();\n \n if (tagName === 'input') {\n return extractInputValue(element as HTMLInputElement, warnings);\n }\n\n if (tagName === 'textarea') {\n return extractTextareaValue(element as HTMLTextAreaElement, warnings);\n }\n\n if (tagName === 'select') {\n return extractSelectValue(element as HTMLSelectElement, warnings);\n }\n\n // Check for aria-valuenow (for range widgets)\n const valueNow = element.getAttribute('aria-valuenow');\n if (valueNow !== null) {\n const current = parseFloat(valueNow);\n if (!isNaN(current)) {\n const valueMin = element.getAttribute('aria-valuemin');\n const valueMax = element.getAttribute('aria-valuemax');\n const valueText = element.getAttribute('aria-valuetext');\n\n return {\n value: {\n current,\n min: valueMin !== null ? parseFloat(valueMin) : undefined,\n max: valueMax !== null ? parseFloat(valueMax) : undefined,\n text: valueText || undefined,\n },\n warnings,\n };\n }\n }\n\n return { value: undefined, warnings };\n}\n\n/**\n * Extracts boolean ARIA attribute.\n * \n * @param element - Element to extract from\n * @param attrName - Attribute name\n * @param warnings - Array to collect warnings\n * @returns Boolean value or undefined\n */\nfunction extractBooleanAttribute(\n element: Element,\n attrName: string,\n warnings: StateExtractionWarning[]\n): boolean | undefined {\n const value = element.getAttribute(attrName);\n if (value === null) {\n return undefined;\n }\n\n const normalized = value.toLowerCase().trim();\n if (normalized === 'true') {\n return true;\n }\n if (normalized === 'false') {\n return false;\n }\n\n warnings.push({\n message: `Invalid ${attrName} value: \"${value}\". Expected \"true\" or \"false\".`,\n element,\n });\n return undefined;\n}\n\n/**\n * Extracts tri-state ARIA attribute (boolean or 'mixed').\n * \n * @param element - Element to extract from\n * @param attrName - Attribute name\n * @param warnings - Array to collect warnings\n * @returns Boolean, 'mixed', or undefined\n */\nfunction extractTriStateAttribute(\n element: Element,\n attrName: string,\n warnings: StateExtractionWarning[]\n): boolean | 'mixed' | undefined {\n const value = element.getAttribute(attrName);\n if (value === null) {\n return undefined;\n }\n\n const normalized = value.toLowerCase().trim();\n if (normalized === 'true') {\n return true;\n }\n if (normalized === 'false') {\n return false;\n }\n if (normalized === 'mixed') {\n return 'mixed';\n }\n\n warnings.push({\n message: `Invalid ${attrName} value: \"${value}\". Expected \"true\", \"false\", or \"mixed\".`,\n element,\n });\n return undefined;\n}\n\n/**\n * Extracts aria-current attribute.\n * \n * @param element - Element to extract from\n * @param warnings - Array to collect warnings\n * @returns Current value or undefined\n */\nfunction extractCurrentAttribute(\n element: Element,\n warnings: StateExtractionWarning[]\n): 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | false | undefined {\n const value = element.getAttribute('aria-current');\n if (value === null) {\n return undefined;\n }\n\n const normalized = value.toLowerCase().trim();\n const validValues = ['page', 'step', 'location', 'date', 'time', 'true', 'false'];\n\n if (validValues.includes(normalized)) {\n return normalized === 'false' ? false : (normalized as any);\n }\n\n warnings.push({\n message: `Invalid aria-current value: \"${value}\". Expected one of: ${validValues.join(', ')}.`,\n element,\n });\n return undefined;\n}\n\n/**\n * Extracts aria-level attribute for headings.\n * \n * @param element - Element to extract from\n * @param warnings - Array to collect warnings\n * @returns Level (1-6) or undefined\n */\nfunction extractLevelAttribute(\n element: Element,\n warnings: StateExtractionWarning[]\n): number | undefined {\n // Check aria-level attribute\n const ariaLevel = element.getAttribute('aria-level');\n if (ariaLevel !== null) {\n const level = parseInt(ariaLevel, 10);\n if (!isNaN(level) && level >= 1 && level <= 6) {\n return level;\n }\n warnings.push({\n message: `Invalid aria-level value: \"${ariaLevel}\". Expected integer 1-6.`,\n element,\n });\n return undefined;\n }\n\n // Check native heading level\n const tagName = element.tagName.toLowerCase();\n const match = tagName.match(/^h([1-6])$/);\n if (match) {\n return parseInt(match[1], 10);\n }\n\n return undefined;\n}\n\n/**\n * Extracts numeric ARIA attribute.\n * \n * @param element - Element to extract from\n * @param attrName - Attribute name\n * @param warnings - Array to collect warnings\n * @returns Number or undefined\n */\nfunction extractNumberAttribute(\n element: Element,\n attrName: string,\n warnings: StateExtractionWarning[]\n): number | undefined {\n const value = element.getAttribute(attrName);\n if (value === null) {\n return undefined;\n }\n\n const num = parseInt(value, 10);\n if (isNaN(num) || num < 1) {\n warnings.push({\n message: `Invalid ${attrName} value: \"${value}\". Expected positive integer.`,\n element,\n });\n return undefined;\n }\n\n return num;\n}\n\n/**\n * Extracts native element states (checked, disabled, etc.).\n * \n * @param element - Element to extract from\n * @param state - State object to populate\n * @param warnings - Array to collect warnings\n */\nfunction extractNativeStates(\n element: Element,\n state: AccessibleState,\n _warnings: StateExtractionWarning[]\n): void {\n const tagName = element.tagName.toLowerCase();\n\n // Native checked state for checkboxes and radios\n if (tagName === 'input') {\n const input = element as HTMLInputElement;\n const type = input.type.toLowerCase();\n\n if (type === 'checkbox' || type === 'radio') {\n // Only set if not already set by aria-checked\n if (state.checked === undefined) {\n state.checked = input.checked;\n }\n }\n }\n\n // Native disabled state\n if ('disabled' in element) {\n const htmlElement = element as HTMLInputElement | HTMLButtonElement | HTMLSelectElement | HTMLTextAreaElement;\n // Only set if not already set by aria-disabled\n if (state.disabled === undefined && htmlElement.disabled) {\n state.disabled = true;\n }\n }\n\n // Native required state\n if ('required' in element) {\n const htmlElement = element as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n // Only set if not already set by aria-required\n if (state.required === undefined && htmlElement.required) {\n state.required = true;\n }\n }\n\n // Native readonly state\n if ('readOnly' in element) {\n const htmlElement = element as HTMLInputElement | HTMLTextAreaElement;\n // Only set if not already set by aria-readonly\n if (state.readonly === undefined && htmlElement.readOnly) {\n state.readonly = true;\n }\n }\n}\n\n/**\n * Extracts value from input element.\n */\nfunction extractInputValue(\n input: HTMLInputElement,\n warnings: StateExtractionWarning[]\n): ValueExtractionResult {\n const type = input.type.toLowerCase();\n\n // Checkbox and radio use checked state, not value\n if (type === 'checkbox' || type === 'radio') {\n return { value: undefined, warnings };\n }\n\n // Button types don't have meaningful values\n if (type === 'button' || type === 'submit' || type === 'reset') {\n return { value: undefined, warnings };\n }\n\n // Text-like inputs\n const value = input.value;\n if (value) {\n return {\n value: {\n current: value,\n text: value,\n },\n warnings,\n };\n }\n\n return { value: undefined, warnings };\n}\n\n/**\n * Extracts value from textarea element.\n */\nfunction extractTextareaValue(\n textarea: HTMLTextAreaElement,\n warnings: StateExtractionWarning[]\n): ValueExtractionResult {\n const value = textarea.value;\n if (value) {\n return {\n value: {\n current: value,\n text: value,\n },\n warnings,\n };\n }\n\n return { value: undefined, warnings };\n}\n\n/**\n * Extracts value from select element.\n */\nfunction extractSelectValue(\n select: HTMLSelectElement,\n warnings: StateExtractionWarning[]\n): ValueExtractionResult {\n const value = select.value;\n const selectedOption = select.options[select.selectedIndex];\n const text = selectedOption?.textContent || value;\n\n if (value) {\n return {\n value: {\n current: value,\n text,\n },\n warnings,\n };\n }\n\n return { value: undefined, warnings };\n}\n","/**\n * Focus information extraction.\n * \n * Determines focusability and tabindex for elements.\n */\n\nimport type { FocusInfo } from '../model/types.js';\n\n/**\n * Natively focusable element types.\n */\nconst NATIVELY_FOCUSABLE_ELEMENTS = [\n 'a',\n 'button',\n 'input',\n 'select',\n 'textarea',\n 'area',\n 'iframe',\n 'object',\n 'embed',\n 'audio',\n 'video',\n];\n\n/**\n * Extracts focus information from an element.\n * \n * Determines if an element is focusable and extracts explicit tabindex.\n * \n * @param element - Element to extract focus info from\n * @returns Focus information\n */\nexport function extractFocusInfo(element: Element): FocusInfo {\n const tabindexAttr = element.getAttribute('tabindex');\n const tabindex = tabindexAttr !== null ? parseInt(tabindexAttr, 10) : undefined;\n\n // Determine focusability\n const focusable = isFocusable(element, tabindex);\n\n // Only include tabindex if explicitly set\n return {\n focusable,\n ...(tabindexAttr !== null && !isNaN(tabindex!) && { tabindex }),\n };\n}\n\n/**\n * Determines if an element is focusable.\n * \n * An element is focusable if:\n * - It's a natively focusable element (and not disabled)\n * - It has tabindex >= 0\n * - It has tabindex = -1 (programmatically focusable)\n * \n * @param element - Element to check\n * @param tabindex - Parsed tabindex value\n * @returns true if element is focusable\n */\nfunction isFocusable(element: Element, tabindex: number | undefined): boolean {\n const tagName = element.tagName.toLowerCase();\n\n // Check if element is disabled\n if (isDisabled(element)) {\n return false;\n }\n\n // Explicit tabindex makes element focusable (including -1 for programmatic focus)\n if (tabindex !== undefined && !isNaN(tabindex)) {\n return true;\n }\n\n // Check if natively focusable\n if (isNativelyFocusable(element, tagName)) {\n return true;\n }\n\n // Elements with explicit ARIA roles may be focusable\n // For now, we'll be conservative and only mark as focusable if tabindex is set\n return false;\n}\n\n/**\n * Checks if an element is natively focusable.\n * \n * @param element - Element to check\n * @param tagName - Tag name (lowercase)\n * @returns true if natively focusable\n */\nfunction isNativelyFocusable(element: Element, tagName: string): boolean {\n // Links must have href to be focusable\n if (tagName === 'a' || tagName === 'area') {\n return element.hasAttribute('href');\n }\n\n // Check if in the list of natively focusable elements\n if (NATIVELY_FOCUSABLE_ELEMENTS.includes(tagName)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Checks if an element is disabled.\n * \n * @param element - Element to check\n * @returns true if disabled\n */\nfunction isDisabled(element: Element): boolean {\n // Check native disabled attribute\n if ('disabled' in element) {\n const htmlElement = element as HTMLInputElement | HTMLButtonElement | HTMLSelectElement | HTMLTextAreaElement;\n if (htmlElement.disabled) {\n return true;\n }\n }\n\n // Check aria-disabled\n const ariaDisabled = element.getAttribute('aria-disabled');\n if (ariaDisabled === 'true') {\n return true;\n }\n\n return false;\n}\n","/**\n * Accessibility tree builder.\n * \n * Builds the complete accessibility tree from a DOM tree by integrating\n * all extraction components (role, name, description, state, value, focus).\n * \n * Supports transparent traversal through role-less elements, text node\n * capture as staticText nodes, shadow DOM traversal, and CSS hidden state.\n */\n\nimport type { AccessibleNode, AnnouncementModel } from '../model/types.js';\nimport { CURRENT_MODEL_VERSION } from '../model/types.js';\nimport { computeAccessibleName, computeAccessibleDescription } from './aria-name.js';\nimport { computeRole, isAccessible } from './role-mapper.js';\nimport { extractState, extractValue } from './state-extractor.js';\nimport { extractFocusInfo } from './focus-extractor.js';\n\n/**\n * Warning emitted during tree building.\n */\nexport interface TreeBuildWarning {\n message: string;\n element: Element;\n}\n\n/**\n * Result of tree building.\n */\nexport interface TreeBuildResult {\n model: AnnouncementModel;\n warnings: TreeBuildWarning[];\n}\n\n/**\n * Error thrown when selector filtering fails.\n */\nexport class SelectorError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SelectorError';\n }\n}\n\n/**\n * Checks whether an element is hidden from the accessibility tree.\n * \n * Checks aria-hidden=\"true\", display: none, and visibility: hidden.\n * Gracefully skips CSS checks when getComputedStyle is unavailable.\n * \n * @param element - Element to check\n * @returns true if the element is hidden\n */\nfunction isHidden(element: Element): boolean {\n // Check aria-hidden on element itself\n if (element.getAttribute('aria-hidden') === 'true') return true;\n\n // Check CSS hidden state if getComputedStyle is available\n if (typeof getComputedStyle === 'function') {\n try {\n const style = getComputedStyle(element);\n if (style.display === 'none') return true;\n if (style.visibility === 'hidden') return true;\n } catch {\n // Environment doesn't support getComputedStyle — skip CSS checks\n }\n }\n\n return false;\n}\n\n/**\n * Processes a single child node (Text or Element) and appends resulting\n * AccessibleNodes to the children array.\n * \n * For Text nodes: creates a staticText AccessibleNode with trimmed text.\n * For Element nodes: checks hidden/accessible state; if role-less, does\n * transparent traversal via collectChildrenFromRolelessElement.\n * \n * @param node - DOM node to process\n * @param children - Array to append resulting AccessibleNodes to\n * @param warnings - Array to collect warnings\n */\nfunction processChildNode(\n node: Node,\n children: AccessibleNode[],\n warnings: TreeBuildWarning[]\n): void {\n if (node.nodeType === 3) { // TEXT_NODE\n const text = (node.textContent || '').trim();\n if (text.length > 0) {\n children.push({\n role: 'staticText',\n name: text,\n state: {},\n focus: { focusable: false },\n children: [],\n });\n }\n return;\n }\n if (node.nodeType === 1) { // ELEMENT_NODE\n const element = node as Element;\n if (isHidden(element)) return;\n if (!isAccessible(element)) {\n // Transparent traversal: collect children from role-less element\n const grandchildren = collectChildrenFromRolelessElement(element, warnings);\n children.push(...grandchildren);\n return;\n }\n const childNode = buildNodeRecursive(element, warnings);\n if (childNode) children.push(childNode);\n }\n}\n\n/**\n * Collects accessible children from a role-less element (transparent traversal).\n * \n * Traverses shadow DOM first (if present), then light DOM childNodes.\n * Returns a flat array of AccessibleNodes to be merged into the parent's children.\n * \n * @param element - Role-less element to collect children from\n * @param warnings - Array to collect warnings\n * @returns Flat array of AccessibleNodes\n */\nfunction collectChildrenFromRolelessElement(\n element: Element,\n warnings: TreeBuildWarning[]\n): AccessibleNode[] {\n return collectAccessibleChildren(element, warnings);\n}\n\n/**\n * Centralized, slot-aware child collection for an element.\n *\n * Behavior:\n * - If the element has an open shadow root, traverse the shadow tree. When a\n * `<slot>` is encountered, resolve its assigned (projected light-DOM) nodes\n * via `assignedNodes({ flatten: true })` and process them in place, so\n * slotted content appears in shadow-tree order. If a slot has no assigned\n * nodes, its default content is used. Slotted light-DOM nodes are therefore\n * emitted exactly once (at the slot position), never again from the host's\n * light DOM.\n * - If the element has no shadow root, traverse the light-DOM childNodes as\n * before.\n *\n * `assignedNodes`/`shadowRoot` are feature-detected so environments with\n * limited shadow DOM support (e.g. jsdom) degrade gracefully.\n *\n * @param element - Element whose accessible children to collect\n * @param warnings - Array to collect warnings\n * @returns Flat array of AccessibleNodes\n */\nfunction collectAccessibleChildren(\n element: Element,\n warnings: TreeBuildWarning[]\n): AccessibleNode[] {\n const children: AccessibleNode[] = [];\n\n // Open shadow root present: traverse the shadow tree only. Slots pull in the\n // projected light-DOM nodes, so we must NOT also walk the host's light DOM.\n if (element.shadowRoot) {\n for (const child of Array.from(element.shadowRoot.childNodes)) {\n processShadowNode(child, children, warnings);\n }\n return children;\n }\n\n // No shadow root. If this is a custom element (tag contains a hyphen) with\n // no light-DOM children, it likely has a *closed* shadow root whose content\n // we cannot traverse. Emit a warning so partial coverage is not mistaken for\n // full coverage, then continue (never throw).\n if (\n element.localName &&\n element.localName.includes('-') &&\n element.childNodes.length === 0\n ) {\n warnings.push({\n message: `Custom element <${element.localName}> has no accessible children and may have a closed shadow root; its content could not be analyzed.`,\n element,\n });\n }\n\n // Plain light-DOM traversal.\n for (const child of Array.from(element.childNodes)) {\n processChildNode(child, children, warnings);\n }\n return children;\n}\n\n/**\n * Processes a node encountered while traversing a shadow tree.\n *\n * Behaves like `processChildNode`, except that `<slot>` elements are expanded\n * into their assigned (projected) light-DOM nodes, or their default content\n * when nothing is assigned.\n */\nfunction processShadowNode(\n node: Node,\n children: AccessibleNode[],\n warnings: TreeBuildWarning[]\n): void {\n if (node.nodeType === 1) {\n const element = node as Element;\n if (element.localName === 'slot') {\n const slot = element as HTMLSlotElement;\n let assigned: Node[] = [];\n // Feature-detect assignedNodes (unavailable in some DOM implementations).\n if (typeof slot.assignedNodes === 'function') {\n try {\n assigned = Array.from(slot.assignedNodes({ flatten: true }));\n } catch {\n assigned = [];\n }\n }\n if (assigned.length > 0) {\n // Projected light-DOM content: process at the slot's position.\n for (const assignedNode of assigned) {\n processChildNode(assignedNode, children, warnings);\n }\n } else {\n // No assigned nodes: fall back to the slot's default content.\n for (const child of Array.from(slot.childNodes)) {\n processShadowNode(child, children, warnings);\n }\n }\n return;\n }\n }\n // Non-slot nodes traverse normally (including nested shadow roots via\n // processChildNode -> buildNodeRecursive/collectAccessibleChildren).\n processChildNode(node, children, warnings);\n}\n\n/**\n * Builds an accessibility tree from a DOM element.\n * \n * Traverses the DOM tree depth-first, applies all extractors,\n * filters inaccessible elements, and builds the hierarchical tree.\n * \n * @param rootElement - Root DOM element to build tree from\n * @param sourceHash - Optional hash of source HTML for change detection\n * @returns Announcement model and warnings\n */\nexport function buildAccessibilityTree(\n rootElement: Element,\n sourceHash?: string\n): TreeBuildResult {\n const warnings: TreeBuildWarning[] = [];\n \n // If root element is hidden, return empty generic container\n if (isHidden(rootElement)) {\n const model: AnnouncementModel = {\n version: CURRENT_MODEL_VERSION,\n root: {\n role: 'generic',\n name: '',\n state: {},\n focus: { focusable: false },\n children: [],\n },\n metadata: {\n extractedAt: new Date().toISOString(),\n ...(sourceHash && { sourceHash }),\n },\n };\n return { model, warnings };\n }\n\n // Build the root node\n const rootNode = buildNodeRecursive(rootElement, warnings);\n \n // If root element is not accessible, create a generic container\n const accessibleRoot = rootNode || createGenericContainer(rootElement, warnings);\n \n // Create the announcement model\n const model: AnnouncementModel = {\n version: CURRENT_MODEL_VERSION,\n root: accessibleRoot,\n metadata: {\n extractedAt: new Date().toISOString(),\n ...(sourceHash && { sourceHash }),\n },\n };\n \n return { model, warnings };\n}\n\n/**\n * Builds accessibility trees for elements matching a CSS selector.\n * \n * Uses querySelector/querySelectorAll to find matching elements,\n * then builds an accessibility tree for each match.\n * \n * @param rootElement - Root DOM element to search within\n * @param selector - CSS selector to match elements\n * @param sourceHash - Optional hash of source HTML for change detection\n * @returns Array of announcement models and warnings\n * @throws SelectorError if no elements match the selector\n */\nexport function buildAccessibilityTreeWithSelector(\n rootElement: Element,\n selector: string,\n sourceHash?: string\n): TreeBuildResult[] {\n const document = rootElement.ownerDocument;\n if (!document) {\n throw new SelectorError('Element has no owner document');\n }\n \n // Find all matching elements\n let matchingElements: Element[];\n try {\n // Check if rootElement itself matches\n if (rootElement.matches(selector)) {\n matchingElements = [rootElement];\n } else {\n // Query for matching descendants\n matchingElements = Array.from(rootElement.querySelectorAll(selector));\n }\n } catch (error) {\n throw new SelectorError(`Invalid CSS selector: \"${selector}\". ${error instanceof Error ? error.message : String(error)}`);\n }\n \n // Error if no matches found\n if (matchingElements.length === 0) {\n throw new SelectorError(`No elements match selector: \"${selector}\"`);\n }\n \n // Build accessibility tree for each matching element\n const results: TreeBuildResult[] = [];\n for (const element of matchingElements) {\n const result = buildAccessibilityTree(element, sourceHash);\n results.push(result);\n }\n \n return results;\n}\n\n/**\n * Recursively builds an accessible node from a DOM element.\n * \n * Checks hidden state first, then accessibility. If the element has no role,\n * transparent traversal is not done here (it's handled by processChildNode\n * in the parent's iteration). This function is only called for elements\n * that are known to be accessible.\n * \n * @param element - DOM element to build node from\n * @param warnings - Array to collect warnings\n * @returns Accessible node or null if element is hidden or not accessible\n */\nfunction buildNodeRecursive(\n element: Element,\n warnings: TreeBuildWarning[]\n): AccessibleNode | null {\n // Check hidden state first (before any extraction)\n if (isHidden(element)) {\n return null;\n }\n\n // Check if element should be included in accessibility tree\n if (!isAccessible(element)) {\n return null;\n }\n \n // Extract role\n const roleResult = computeRole(element);\n warnings.push(...roleResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // If no role, element is not accessible\n if (!roleResult.role) {\n return null;\n }\n \n // Extract accessible name\n const nameResult = computeAccessibleName(element);\n warnings.push(...nameResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // Extract accessible description\n const descResult = computeAccessibleDescription(element);\n warnings.push(...descResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // Extract state\n const stateResult = extractState(element);\n warnings.push(...stateResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // Extract value\n const valueResult = extractValue(element);\n warnings.push(...valueResult.warnings.map(w => ({\n message: w.message,\n element: w.element,\n })));\n \n // Extract focus info\n const focusInfo = extractFocusInfo(element);\n \n // Build children (slot-aware; shadow DOM handled centrally)\n const children = collectAccessibleChildren(element, warnings);\n \n // Create the accessible node\n const node: AccessibleNode = {\n role: roleResult.role,\n name: nameResult.name,\n ...(descResult.description && { description: descResult.description }),\n ...(valueResult.value && { value: valueResult.value }),\n state: stateResult.state,\n focus: focusInfo,\n children,\n };\n \n return node;\n}\n\n/**\n * Creates a generic container node when root element is not accessible.\n * \n * This ensures we always have a valid root node even if the root element\n * itself is not accessible (e.g., a plain div).\n * Uses childNodes and processChildNode for text node and transparent traversal support.\n * \n * @param rootElement - Root DOM element\n * @param warnings - Array to collect warnings\n * @returns Generic container node with accessible children\n */\nfunction createGenericContainer(\n rootElement: Element,\n warnings: TreeBuildWarning[]\n): AccessibleNode {\n // Build children from root element (slot-aware; shadow DOM handled centrally)\n const children = collectAccessibleChildren(rootElement, warnings);\n \n // Create a generic container\n return {\n role: 'generic',\n name: '',\n state: {},\n focus: {\n focusable: false,\n },\n children,\n };\n}\n","/**\n * Runtime Accessibility Timeline - Public API\n *\n * Exports all public types, interfaces, and factory functions for the\n * Runtime Accessibility Engine. This module provides:\n *\n * - Event type system (EventType, AccessibilityEvent, payloads)\n * - Runtime engine (createEngine)\n * - Timeline generation (createTimelineGenerator)\n * - Interaction execution (executeAction, executeSequence)\n * - Built-in patterns (getBuiltinPattern)\n * - Heuristic analysis (createHeuristicAnalyzer)\n * - Serialization (serializeTimeline, deserializeTimeline, etc.)\n * - Stable CSS selector generation (generateSelector)\n */\n\n// Types and interfaces\nexport * from './types.js';\n\n// Engine\nexport { createEngine } from './engine.js';\nexport type { EngineOptions, RuntimeAccessibilityEngine } from './engine.js';\n\n// Timeline Generator\nexport { createTimelineGenerator } from './timeline-generator.js';\nexport type { TimelineGeneratorOptions, TimelineGenerator } from './timeline-generator.js';\n\n// Interaction execution\nexport { executeAction, executeSequence } from './interactions.js';\n\n// Built-in interaction patterns\nexport { getBuiltinPattern } from './patterns.js';\nexport type { PatternSelectorMap, BuiltinPatternName } from './patterns.js';\n\n// Heuristic warning analyzer\nexport { createHeuristicAnalyzer } from './heuristics.js';\nexport type { HeuristicConfig, HeuristicAnalyzer } from './heuristics.js';\n\n// Serialization\nexport {\n serializeTimeline,\n deserializeTimeline,\n serializeEvent,\n deserializeEvent,\n serializeInteractionSequence,\n deserializeInteractionSequence,\n timelinesEqual,\n} from './serialization.js';\n\n// Stable CSS selector generation\nexport { generateSelector } from './selector.js';\n\n// Behavior Diff Engine\nexport { diffTimelines } from './diff-engine.js';\nexport type { BehaviorDiffReport, DiffEntry } from './diff-engine.js';\n\n// Severity Classification\nexport { classifyDiff } from './severity.js';\nexport type { SeverityLevel, ClassifiedDiffEntry, ClassifiedDiffReport } from './severity.js';\n\n// Baseline Storage\nexport { createBaselineStorage } from './baseline-storage.js';\nexport type { BaselineFile, BaselineStorage } from './baseline-storage.js';\n\n// Verbosity Analyzer\nexport { analyzeVerbosity, formatVerbosityReport } from './verbosity-analyzer.js';\nexport type {\n VerbositySeverity,\n VerbosityPattern,\n VerbosityFinding,\n VerbosityReport,\n VerbosityConfig,\n} from './verbosity-analyzer.js';\n","/**\n * Stable CSS Selector Generation\n *\n * Generates unique, deterministic CSS selectors for DOM elements.\n * The selector strategy prioritizes stability and readability:\n *\n * 1. If the element has an ID, return `#id`\n * 2. Walk up from the element to the document root, building a path\n * 3. At each level, try tag name alone, then tag+classes, then tag:nth-child(n)\n * 4. Stop building the path when the partial selector already uniquely identifies the element\n */\n\n/**\n * Generate a stable CSS selector that uniquely identifies the given element\n * within its document.\n *\n * The selector is deterministic: given the same DOM structure, the same element\n * will always produce the same selector string.\n */\nexport function generateSelector(element: Element): string {\n // If the element has an ID, use it directly (IDs are unique within a document)\n if (element.id) {\n return `#${escapeCSSIdentifier(element.id)}`;\n }\n\n const document = element.ownerDocument;\n if (!document) {\n return getTagName(element);\n }\n\n // Build path segments from element up to document root\n const segments: string[] = [];\n let current: Element | null = element;\n\n while (current && current !== document.documentElement) {\n const segment = buildSegment(current, document);\n segments.unshift(segment);\n\n // Check if the current partial path already uniquely identifies the element\n const partialSelector = segments.join(' > ');\n try {\n const matches = document.querySelectorAll(partialSelector);\n if (matches.length === 1 && matches[0] === element) {\n return partialSelector;\n }\n } catch {\n // If querySelectorAll fails (invalid selector), continue building path\n }\n\n current = current.parentElement;\n }\n\n // Include html root if needed\n if (segments.length === 0) {\n return getTagName(element);\n }\n\n const fullSelector = segments.join(' > ');\n\n // Final uniqueness check - if still not unique, shouldn't happen for well-formed DOM\n // but return what we have as it's the most specific path we can build\n return fullSelector;\n}\n\n/**\n * Build a selector segment for a single element in the path.\n * Tries strategies in order of preference: tag alone, tag+classes, tag:nth-child.\n */\nfunction buildSegment(element: Element, _document: Document): string {\n const tag = getTagName(element);\n const parent = element.parentElement;\n\n // Strategy 1: Tag name alone is unique among siblings\n if (parent) {\n const siblingsWithSameTag = Array.from(parent.children).filter(\n (child) => getTagName(child) === tag\n );\n if (siblingsWithSameTag.length === 1) {\n return tag;\n }\n } else {\n // No parent - tag alone is our best option at root level\n return tag;\n }\n\n // Strategy 2: Tag + class combination is unique among siblings\n const classes = getStableClasses(element);\n if (classes.length > 0) {\n const tagWithClasses = `${tag}.${classes.join('.')}`;\n if (parent) {\n const siblingsMatchingClasses = Array.from(parent.children).filter(\n (child) => {\n if (getTagName(child) !== tag) return false;\n return classes.every((cls) => child.classList.contains(cls));\n }\n );\n if (siblingsMatchingClasses.length === 1) {\n return tagWithClasses;\n }\n }\n }\n\n // Strategy 3: nth-child fallback (always unique among siblings)\n const index = getNthChildIndex(element);\n return `${tag}:nth-child(${index})`;\n}\n\n/**\n * Get the lowercase tag name for an element.\n */\nfunction getTagName(element: Element): string {\n return element.tagName.toLowerCase();\n}\n\n/**\n * Get sorted, stable class names for an element.\n * Filters out classes that look dynamic (contain random characters/hashes).\n * Sorting ensures deterministic output regardless of class order in markup.\n */\nfunction getStableClasses(element: Element): string[] {\n const classes = Array.from(element.classList);\n if (classes.length === 0) return [];\n\n // Filter out classes that look like generated hashes (e.g., CSS modules)\n const stableClasses = classes.filter((cls) => !looksLikeDynamicClass(cls));\n\n // Sort for determinism\n return stableClasses.sort().map(escapeCSSIdentifier);\n}\n\n/**\n * Heuristic to detect dynamic/generated class names.\n * Classes with patterns like hex hashes, random strings, or auto-generated\n * suffixes are considered unstable.\n */\nfunction looksLikeDynamicClass(className: string): boolean {\n // Classes that are purely hex strings of 5+ chars\n if (/^[a-f0-9]{5,}$/i.test(className)) return true;\n\n // Classes ending with a hash-like suffix (e.g., \"button_a1b2c3\")\n if (/[_-][a-f0-9]{5,}$/i.test(className)) return true;\n\n // CSS module style hashes (e.g., \"styles__button___2xF3d\")\n if (/_{2,}[A-Za-z0-9]{4,}$/.test(className)) return true;\n\n return false;\n}\n\n/**\n * Get the 1-based nth-child index of an element among its parent's children.\n */\nfunction getNthChildIndex(element: Element): number {\n const parent = element.parentElement;\n if (!parent) return 1;\n\n const children = Array.from(parent.children);\n const index = children.indexOf(element);\n return index + 1;\n}\n\n/**\n * Escape special characters in a CSS identifier.\n * Handles characters that have special meaning in CSS selectors.\n */\nfunction escapeCSSIdentifier(value: string): string {\n // If the value is empty, return it as-is\n if (!value) return value;\n\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n const code = char.charCodeAt(0);\n\n // If it starts with a digit, escape it\n if (i === 0 && code >= 0x30 && code <= 0x39) {\n result += `\\\\3${char} `;\n continue;\n }\n\n // Characters that need escaping in CSS identifiers\n if (\n char === '!' ||\n char === '\"' ||\n char === '#' ||\n char === '$' ||\n char === '%' ||\n char === '&' ||\n char === \"'\" ||\n char === '(' ||\n char === ')' ||\n char === '*' ||\n char === '+' ||\n char === ',' ||\n char === '.' ||\n char === '/' ||\n char === ':' ||\n char === ';' ||\n char === '<' ||\n char === '=' ||\n char === '>' ||\n char === '?' ||\n char === '@' ||\n char === '[' ||\n char === '\\\\' ||\n char === ']' ||\n char === '^' ||\n char === '`' ||\n char === '{' ||\n char === '|' ||\n char === '}' ||\n char === '~' ||\n char === ' '\n ) {\n result += `\\\\${char}`;\n continue;\n }\n\n result += char;\n }\n\n return result;\n}\n","/**\n * Focus Observer\n *\n * Observes focus changes on a document and emits FOCUS_CHANGED accessibility\n * events. Tracks the previously focused element to populate the previousTarget\n * field in each event.\n *\n * @module runtime/observers/focus-observer\n */\n\nimport type { AccessibilityEvent, EventTarget as A11yEventTarget } from '../types';\nimport { generateSelector } from '../selector';\n\n// ---------------------------------------------------------------------------\n// Accessible Name Computation (self-contained)\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the accessible name for an element.\n * Checks aria-label, then aria-labelledby (resolves referenced element textContent),\n * then falls back to the element's own textContent.\n */\nfunction computeAccessibleName(element: Element, document: Document): string {\n // 1. aria-label takes precedence\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n // 2. aria-labelledby: resolve referenced element(s) text content\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy && labelledBy.trim()) {\n const ids = labelledBy.trim().split(/\\s+/);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = document.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n const combined = parts.join(' ');\n if (combined) {\n return combined;\n }\n }\n\n // 3. Fall back to element's own textContent\n const textContent = element.textContent;\n if (textContent && textContent.trim()) {\n return textContent.trim();\n }\n\n return '';\n}\n\n// ---------------------------------------------------------------------------\n// Implicit Role Mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Determine the ARIA role of an element.\n * Checks the explicit `role` attribute first, then falls back to implicit\n * role mapping based on tag name and attributes.\n */\nfunction getElementRole(element: Element): string {\n // Explicit role takes priority\n const explicitRole = element.getAttribute('role');\n if (explicitRole && explicitRole.trim()) {\n return explicitRole.trim();\n }\n\n // Implicit role mapping\n const tagName = element.tagName.toLowerCase();\n\n switch (tagName) {\n case 'button':\n return 'button';\n case 'a':\n return element.hasAttribute('href') ? 'link' : 'generic';\n case 'input': {\n const type = (element.getAttribute('type') || 'text').toLowerCase();\n switch (type) {\n case 'button':\n case 'submit':\n case 'reset':\n case 'image':\n return 'button';\n case 'checkbox':\n return 'checkbox';\n case 'radio':\n return 'radio';\n case 'range':\n return 'slider';\n case 'search':\n return 'searchbox';\n default:\n return 'textbox';\n }\n }\n case 'textarea':\n return 'textbox';\n case 'select':\n return element.hasAttribute('multiple') ? 'listbox' : 'combobox';\n case 'nav':\n return 'navigation';\n case 'main':\n return 'main';\n case 'header':\n return 'banner';\n case 'footer':\n return 'contentinfo';\n case 'aside':\n return 'complementary';\n case 'form':\n return 'form';\n case 'section':\n return element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby')\n ? 'region'\n : 'generic';\n case 'article':\n return 'article';\n case 'dialog':\n return 'dialog';\n case 'table':\n return 'table';\n case 'ul':\n case 'ol':\n return 'list';\n case 'li':\n return 'listitem';\n case 'img':\n return element.getAttribute('alt') === '' ? 'presentation' : 'img';\n case 'h1':\n case 'h2':\n case 'h3':\n case 'h4':\n case 'h5':\n case 'h6':\n return 'heading';\n case 'option':\n return 'option';\n case 'progress':\n return 'progressbar';\n case 'output':\n return 'status';\n case 'menu':\n return 'menu';\n default:\n return 'generic';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Focus Observer\n// ---------------------------------------------------------------------------\n\n/** Callback type for emitting accessibility events from the observer. */\nexport type FocusEventEmitter = (event: AccessibilityEvent) => void;\n\nexport interface FocusObserverOptions {\n /** The document to observe focus changes on */\n document: Document;\n /** Callback to emit accessibility events */\n onEvent: FocusEventEmitter;\n /** Function to get the current timestamp (ms since session start) */\n getTimestamp: () => number;\n}\n\nexport interface FocusObserver {\n /** Start listening for focus changes */\n start(): void;\n /** Stop listening for focus changes */\n stop(): void;\n /** Whether the observer is currently active */\n readonly isActive: boolean;\n}\n\n/**\n * Creates a FocusObserver that listens to focusin events on the document\n * and emits FOCUS_CHANGED accessibility events.\n */\nexport function createFocusObserver(options: FocusObserverOptions): FocusObserver {\n const { document: doc, onEvent, getTimestamp } = options;\n\n let active = false;\n let previousTarget: A11yEventTarget | null = null;\n\n function buildEventTarget(element: Element): A11yEventTarget {\n return {\n role: getElementRole(element),\n accessibleName: computeAccessibleName(element, doc),\n selector: generateSelector(element),\n };\n }\n\n function handleFocusIn(event: Event): void {\n if (!active) return;\n\n const target = event.target;\n if (!target || !(target instanceof doc.defaultView!.Element)) {\n return;\n }\n\n const currentTarget = buildEventTarget(target);\n\n const a11yEvent: AccessibilityEvent = {\n type: 'FOCUS_CHANGED',\n timestamp: getTimestamp(),\n target: currentTarget,\n payload: {\n kind: 'focus_changed',\n previousTarget: previousTarget,\n },\n };\n\n onEvent(a11yEvent);\n previousTarget = currentTarget;\n }\n\n return {\n start(): void {\n if (active) return;\n active = true;\n previousTarget = null;\n doc.addEventListener('focusin', handleFocusIn);\n },\n\n stop(): void {\n if (!active) return;\n active = false;\n doc.removeEventListener('focusin', handleFocusIn);\n },\n\n get isActive(): boolean {\n return active;\n },\n };\n}\n","/**\n * Mutation Observer for Accessibility-Relevant Attribute Changes\n *\n * Wraps MutationObserver to detect changes to:\n * - `role` attribute → emits ROLE_CHANGED events\n * - `aria-label`, `aria-labelledby` → emits ACCESSIBLE_NAME_CHANGED events\n * - `aria-expanded`, `aria-selected`, `aria-checked`, `aria-disabled`, `aria-hidden` → emits STATE_CHANGED events\n *\n * Filters out irrelevant mutations (text content in non-live regions, style changes).\n * Uses `attributeOldValue: true` to capture previous values for diff reporting.\n *\n * @module runtime/observers/mutation-observer\n */\n\nimport type {\n AccessibilityEvent,\n EventTarget as A11yEventTarget,\n RoleChangedPayload,\n AccessibleNameChangedPayload,\n StateChangedPayload,\n} from '../types';\nimport { generateSelector } from '../selector';\n\n// ---------------------------------------------------------------------------\n// Observed attribute sets\n// ---------------------------------------------------------------------------\n\n/** Attribute that triggers ROLE_CHANGED */\nconst ROLE_ATTRIBUTE = 'role';\n\n/** Attributes that trigger ACCESSIBLE_NAME_CHANGED */\nconst NAME_ATTRIBUTES = new Set(['aria-label', 'aria-labelledby']);\n\n/** Attributes that trigger STATE_CHANGED */\nconst STATE_ATTRIBUTES = new Set([\n 'aria-expanded',\n 'aria-selected',\n 'aria-checked',\n 'aria-disabled',\n 'aria-hidden',\n]);\n\n/** All observed attributes combined (for MutationObserver attributeFilter) */\nconst OBSERVED_ATTRIBUTES = [\n ROLE_ATTRIBUTE,\n 'aria-label',\n 'aria-labelledby',\n 'aria-expanded',\n 'aria-selected',\n 'aria-checked',\n 'aria-disabled',\n 'aria-hidden',\n];\n\n// ---------------------------------------------------------------------------\n// Accessible Name Computation (self-contained)\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the accessible name for an element.\n * Checks aria-label, then aria-labelledby (resolves referenced element textContent),\n * then falls back to the element's own textContent.\n */\nfunction computeAccessibleName(element: Element, document: Document): string {\n // 1. aria-label takes precedence\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n // 2. aria-labelledby: resolve referenced element(s) text content\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy && labelledBy.trim()) {\n const ids = labelledBy.trim().split(/\\s+/);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = document.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n const combined = parts.join(' ');\n if (combined) {\n return combined;\n }\n }\n\n // 3. Fall back to element's own textContent\n const textContent = element.textContent;\n if (textContent && textContent.trim()) {\n return textContent.trim();\n }\n\n return '';\n}\n\n// ---------------------------------------------------------------------------\n// Implicit Role Mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Determine the ARIA role of an element.\n * Checks the explicit `role` attribute first, then falls back to implicit\n * role mapping based on tag name and attributes.\n */\nfunction getElementRole(element: Element): string {\n // Explicit role takes priority\n const explicitRole = element.getAttribute('role');\n if (explicitRole && explicitRole.trim()) {\n return explicitRole.trim();\n }\n\n // Implicit role mapping\n const tagName = element.tagName.toLowerCase();\n\n switch (tagName) {\n case 'button':\n return 'button';\n case 'a':\n return element.hasAttribute('href') ? 'link' : 'generic';\n case 'input': {\n const type = (element.getAttribute('type') || 'text').toLowerCase();\n switch (type) {\n case 'button':\n case 'submit':\n case 'reset':\n case 'image':\n return 'button';\n case 'checkbox':\n return 'checkbox';\n case 'radio':\n return 'radio';\n case 'range':\n return 'slider';\n case 'search':\n return 'searchbox';\n default:\n return 'textbox';\n }\n }\n case 'textarea':\n return 'textbox';\n case 'select':\n return element.hasAttribute('multiple') ? 'listbox' : 'combobox';\n case 'nav':\n return 'navigation';\n case 'main':\n return 'main';\n case 'header':\n return 'banner';\n case 'footer':\n return 'contentinfo';\n case 'aside':\n return 'complementary';\n case 'form':\n return 'form';\n case 'section':\n return element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby')\n ? 'region'\n : 'generic';\n case 'article':\n return 'article';\n case 'dialog':\n return 'dialog';\n case 'table':\n return 'table';\n case 'ul':\n case 'ol':\n return 'list';\n case 'li':\n return 'listitem';\n case 'img':\n return element.getAttribute('alt') === '' ? 'presentation' : 'img';\n case 'h1':\n case 'h2':\n case 'h3':\n case 'h4':\n case 'h5':\n case 'h6':\n return 'heading';\n case 'option':\n return 'option';\n case 'progress':\n return 'progressbar';\n case 'output':\n return 'status';\n case 'menu':\n return 'menu';\n default:\n return 'generic';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Mutation Observer Types\n// ---------------------------------------------------------------------------\n\n/** Callback type for emitting accessibility events from the observer. */\nexport type MutationEventEmitter = (event: AccessibilityEvent) => void;\n\nexport interface MutationObserverOptions {\n /** The document to observe attribute changes on */\n document: Document;\n /** Callback to emit accessibility events */\n onEvent: MutationEventEmitter;\n /** Function to get the current timestamp (ms since session start) */\n getTimestamp: () => number;\n}\n\nexport interface AccessibilityMutationObserver {\n /** Start observing the document for attribute mutations */\n start(): void;\n /** Stop observing and disconnect the MutationObserver */\n stop(): void;\n /** Whether the observer is currently active */\n readonly isActive: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Mutation Observer Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an accessibility-focused MutationObserver that watches for\n * role, accessible name, and ARIA state attribute changes, emitting\n * normalized accessibility events.\n *\n * Only observes attribute mutations on the specific ARIA attributes listed.\n * Text content changes, style changes, and child list mutations are ignored.\n */\nexport function createMutationObserver(\n options: MutationObserverOptions\n): AccessibilityMutationObserver {\n const { document: doc, onEvent, getTimestamp } = options;\n\n let observer: MutationObserver | null = null;\n let active = false;\n\n function handleMutations(mutations: MutationRecord[]): void {\n if (!active) return;\n\n for (const mutation of mutations) {\n if (mutation.type !== 'attributes') {\n continue;\n }\n\n const attributeName = mutation.attributeName;\n if (!attributeName) {\n continue;\n }\n\n const target = mutation.target;\n if (!(target instanceof Element)) {\n continue;\n }\n\n // Route to the appropriate handler based on attribute category\n if (attributeName === ROLE_ATTRIBUTE) {\n handleRoleChange(target, mutation.oldValue);\n } else if (NAME_ATTRIBUTES.has(attributeName)) {\n handleNameChange(target, attributeName, mutation.oldValue);\n } else if (STATE_ATTRIBUTES.has(attributeName)) {\n handleStateChange(target, attributeName, mutation.oldValue);\n }\n // All other attributes are filtered out by the attributeFilter config\n }\n }\n\n function handleRoleChange(element: Element, oldValue: string | null): void {\n const previousRole = oldValue?.trim() || getImplicitRole(element);\n const newRole = element.getAttribute('role')?.trim() || getImplicitRole(element);\n\n // Don't emit if the effective role hasn't actually changed\n if (previousRole === newRole) {\n return;\n }\n\n const eventTarget = buildEventTarget(element);\n const payload: RoleChangedPayload = {\n kind: 'role_changed',\n previousRole,\n newRole,\n };\n\n onEvent({\n type: 'ROLE_CHANGED',\n timestamp: getTimestamp(),\n target: eventTarget,\n payload,\n });\n }\n\n function handleNameChange(\n element: Element,\n attributeName: string,\n oldValue: string | null\n ): void {\n let previousName: string;\n let newName: string;\n\n if (attributeName === 'aria-label') {\n // For aria-label changes, the old value is the previous label\n previousName = oldValue?.trim() || '';\n newName = computeAccessibleName(element, doc);\n\n // If old value was empty, try to compute what the name was from other sources\n if (!previousName && oldValue === null) {\n // aria-label was just added; previous name was from labelledby or textContent\n // We can approximate by checking other sources\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy) {\n previousName = resolveAriaLabelledBy(element, labelledBy);\n } else {\n previousName = element.textContent?.trim() || '';\n }\n }\n } else {\n // aria-labelledby changed\n // Resolve the old labelledby references for the previous name\n previousName = oldValue ? resolveAriaLabelledBy(element, oldValue) : '';\n if (!previousName && oldValue === null) {\n // aria-labelledby was just added; previous name was from aria-label or textContent\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel) {\n previousName = ariaLabel.trim();\n } else {\n previousName = element.textContent?.trim() || '';\n }\n }\n newName = computeAccessibleName(element, doc);\n }\n\n // Don't emit if the accessible name hasn't actually changed\n if (previousName === newName) {\n return;\n }\n\n const eventTarget = buildEventTarget(element);\n const payload: AccessibleNameChangedPayload = {\n kind: 'accessible_name_changed',\n previousName,\n newName,\n };\n\n onEvent({\n type: 'ACCESSIBLE_NAME_CHANGED',\n timestamp: getTimestamp(),\n target: eventTarget,\n payload,\n });\n }\n\n function handleStateChange(\n element: Element,\n attributeName: string,\n oldValue: string | null\n ): void {\n const currentValue = element.getAttribute(attributeName);\n\n // Normalize values: treat \"true\"/\"false\" as booleans\n const normalizedOld = normalizeStateValue(oldValue);\n const normalizedNew = normalizeStateValue(currentValue);\n\n // Don't emit if the state hasn't actually changed\n if (normalizedOld === normalizedNew) {\n return;\n }\n\n const eventTarget = buildEventTarget(element);\n const payload: StateChangedPayload = {\n kind: 'state_changed',\n attribute: attributeName,\n previousValue: normalizedOld,\n newValue: normalizedNew,\n };\n\n onEvent({\n type: 'STATE_CHANGED',\n timestamp: getTimestamp(),\n target: eventTarget,\n payload,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n function buildEventTarget(element: Element): A11yEventTarget {\n return {\n role: getElementRole(element),\n accessibleName: computeAccessibleName(element, doc),\n selector: generateSelector(element),\n };\n }\n\n /**\n * Get the implicit role for an element based on tag name.\n * Used as fallback when the explicit role attribute is absent.\n */\n function getImplicitRole(element: Element): string {\n const tagName = element.tagName.toLowerCase();\n switch (tagName) {\n case 'button':\n return 'button';\n case 'a':\n return element.hasAttribute('href') ? 'link' : 'generic';\n case 'input': {\n const type = (element.getAttribute('type') || 'text').toLowerCase();\n switch (type) {\n case 'button':\n case 'submit':\n case 'reset':\n case 'image':\n return 'button';\n case 'checkbox':\n return 'checkbox';\n case 'radio':\n return 'radio';\n default:\n return 'textbox';\n }\n }\n default:\n return 'generic';\n }\n }\n\n function resolveAriaLabelledBy(\n element: Element,\n idRefs: string\n ): string {\n const ownerDoc = element.ownerDocument;\n if (!ownerDoc) {\n return '';\n }\n\n const ids = idRefs.trim().split(/\\s+/).filter(Boolean);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = ownerDoc.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n\n return parts.join(' ');\n }\n\n function normalizeStateValue(value: string | null): string | boolean | null {\n if (value === null) {\n return null;\n }\n if (value === 'true') {\n return true;\n }\n if (value === 'false') {\n return false;\n }\n return value;\n }\n\n // ---------------------------------------------------------------------------\n // Public interface\n // ---------------------------------------------------------------------------\n\n return {\n start(): void {\n if (active) return;\n active = true;\n\n observer = new MutationObserver(handleMutations);\n observer.observe(doc.body ?? doc.documentElement, {\n attributes: true,\n attributeOldValue: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n subtree: true,\n });\n },\n\n stop(): void {\n if (!active) return;\n active = false;\n\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n },\n\n get isActive(): boolean {\n return active;\n },\n };\n}\n","/**\n * Live Region Observer\n *\n * Detects text content changes within elements marked with aria-live or\n * implicit live region roles (alert, status, log, marquee, timer).\n * Emits ANNOUNCEMENT events with politeness level and announced text.\n *\n * Handles:\n * - Elements with explicit aria-live attribute (polite/assertive)\n * - Elements with role=\"alert\" (implicit assertive)\n * - Elements with role=\"status\"/\"log\"/\"marquee\"/\"timer\" (implicit polite)\n * - aria-atomic=\"true\" (read entire region vs changed nodes only)\n * - Dynamically added live regions (watched via document-level observer)\n */\n\nimport type { AccessibilityEvent, EventTarget as A11yEventTarget } from '../types';\nimport { generateSelector } from '../selector';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Callback invoked when the observer detects a live region announcement. */\nexport type LiveRegionEventCallback = (event: Omit<AccessibilityEvent, 'timestamp'>) => void;\n\n/** Roles that implicitly create live regions. */\nconst IMPLICIT_LIVE_ROLES = new Set(['alert', 'status', 'log', 'marquee', 'timer']);\n\n/** Map from implicit role to politeness level. */\nconst ROLE_POLITENESS_MAP: Record<string, 'polite' | 'assertive'> = {\n alert: 'assertive',\n status: 'polite',\n log: 'polite',\n marquee: 'polite',\n timer: 'polite',\n};\n\n// ---------------------------------------------------------------------------\n// Observer Interface\n// ---------------------------------------------------------------------------\n\nexport interface LiveRegionObserver {\n /** Start observing live regions for content changes. */\n start(): void;\n /** Stop observing and clean up all mutation observers. */\n stop(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a live region observer that watches for content changes in\n * aria-live regions and emits ANNOUNCEMENT events.\n *\n * @param document - The document to observe\n * @param callback - Function called with AccessibilityEvent for each announcement\n * @returns LiveRegionObserver with start/stop lifecycle methods\n */\nexport function createLiveRegionObserver(\n document: Document,\n callback: LiveRegionEventCallback\n): LiveRegionObserver {\n /** MutationObserver for content changes within known live regions. */\n let contentObserver: MutationObserver | null = null;\n\n /** MutationObserver for detecting new live regions added to the document. */\n let documentObserver: MutationObserver | null = null;\n\n /** Set of currently tracked live region elements. */\n const trackedRegions = new Set<Element>();\n\n // -------------------------------------------------------------------------\n // Helpers\n // -------------------------------------------------------------------------\n\n /**\n * Determine if an element is a live region and return its politeness level.\n * Returns null if the element is not a live region.\n */\n function getLiveRegionPoliteness(element: Element): 'polite' | 'assertive' | null {\n // Explicit aria-live takes precedence\n const ariaLive = element.getAttribute('aria-live');\n if (ariaLive === 'assertive') return 'assertive';\n if (ariaLive === 'polite') return 'polite';\n // aria-live=\"off\" means not a live region\n if (ariaLive === 'off') return null;\n\n // Check implicit live region roles\n const role = element.getAttribute('role');\n if (role && IMPLICIT_LIVE_ROLES.has(role)) {\n return ROLE_POLITENESS_MAP[role] || 'polite';\n }\n\n // If aria-live has another value (non-standard), treat as polite\n if (ariaLive && ariaLive !== 'off') return 'polite';\n\n return null;\n }\n\n /**\n * Determine whether the live region uses atomic reading\n * (entire region text vs only changed nodes).\n */\n function isAtomic(element: Element): boolean {\n return element.getAttribute('aria-atomic') === 'true';\n }\n\n /**\n * Build the EventTarget info for a live region element.\n */\n function buildEventTarget(element: Element): A11yEventTarget {\n const role = element.getAttribute('role') || 'region';\n const accessibleName =\n element.getAttribute('aria-label') ||\n element.getAttribute('aria-labelledby') ||\n '';\n const selector = generateSelector(element);\n\n return { role, accessibleName, selector };\n }\n\n /**\n * Extract text content from a list of added nodes (text nodes and elements).\n */\n function getTextFromNodes(nodes: NodeList): string {\n const parts: string[] = [];\n nodes.forEach((node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent?.trim();\n if (text) parts.push(text);\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n const text = (node as Element).textContent?.trim();\n if (text) parts.push(text);\n }\n });\n return parts.join(' ').trim();\n }\n\n /**\n * Emit an ANNOUNCEMENT event for a live region content change.\n */\n function emitAnnouncement(\n liveRegion: Element,\n text: string,\n politeness: 'polite' | 'assertive'\n ): void {\n if (!text) return;\n\n const target = buildEventTarget(liveRegion);\n\n callback({\n type: 'ANNOUNCEMENT',\n target,\n payload: {\n kind: 'announcement',\n politeness,\n text,\n },\n });\n }\n\n /**\n * Find the closest ancestor (or self) that is a tracked live region.\n */\n function findLiveRegionAncestor(node: Node): Element | null {\n let current: Node | null = node;\n while (current) {\n if (current.nodeType === Node.ELEMENT_NODE && trackedRegions.has(current as Element)) {\n return current as Element;\n }\n current = current.parentNode;\n }\n return null;\n }\n\n // -------------------------------------------------------------------------\n // Content Mutation Handling\n // -------------------------------------------------------------------------\n\n /**\n * Handle mutations within tracked live regions.\n */\n function handleContentMutations(mutations: MutationRecord[]): void {\n // Group mutations by their live region ancestor to avoid duplicate announcements\n const regionChanges = new Map<Element, { addedText: string[]; charDataChanged: boolean }>();\n\n for (const mutation of mutations) {\n const liveRegion = findLiveRegionAncestor(mutation.target);\n if (!liveRegion) continue;\n\n if (!regionChanges.has(liveRegion)) {\n regionChanges.set(liveRegion, { addedText: [], charDataChanged: false });\n }\n const changes = regionChanges.get(liveRegion)!;\n\n if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {\n const text = getTextFromNodes(mutation.addedNodes);\n if (text) {\n changes.addedText.push(text);\n }\n } else if (mutation.type === 'characterData') {\n changes.charDataChanged = true;\n }\n }\n\n // Emit announcements for each live region that had changes\n for (const [region, changes] of regionChanges) {\n const politeness = getLiveRegionPoliteness(region);\n if (!politeness) continue;\n\n let text: string;\n if (isAtomic(region)) {\n // aria-atomic=\"true\": read the entire region's text content\n text = region.textContent?.trim() || '';\n } else {\n // Non-atomic: only announce changed/added content\n if (changes.addedText.length > 0) {\n text = changes.addedText.join(' ').trim();\n } else if (changes.charDataChanged) {\n // characterData changed but no new nodes — read updated text\n text = region.textContent?.trim() || '';\n } else {\n text = '';\n }\n }\n\n emitAnnouncement(region, text, politeness);\n }\n }\n\n // -------------------------------------------------------------------------\n // Document Mutation Handling (detect new live regions)\n // -------------------------------------------------------------------------\n\n /**\n * Handle document-level mutations to detect new live regions being added.\n */\n function handleDocumentMutations(mutations: MutationRecord[]): void {\n for (const mutation of mutations) {\n if (mutation.type !== 'childList') continue;\n\n mutation.addedNodes.forEach((node) => {\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const element = node as Element;\n\n // Check if the added element itself is a live region\n if (getLiveRegionPoliteness(element) !== null && !trackedRegions.has(element)) {\n trackRegion(element);\n }\n\n // Check descendants for live regions\n const descendants = element.querySelectorAll('[aria-live], [role]');\n descendants.forEach((desc) => {\n if (getLiveRegionPoliteness(desc) !== null && !trackedRegions.has(desc)) {\n trackRegion(desc);\n }\n });\n });\n\n // Handle removed nodes: untrack regions that are removed from DOM\n mutation.removedNodes.forEach((node) => {\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const element = node as Element;\n\n if (trackedRegions.has(element)) {\n trackedRegions.delete(element);\n }\n\n // Remove descendants\n const descendants = element.querySelectorAll('[aria-live], [role]');\n descendants.forEach((desc) => {\n trackedRegions.delete(desc);\n });\n });\n }\n }\n\n /**\n * Track a new live region element.\n */\n function trackRegion(element: Element): void {\n trackedRegions.add(element);\n }\n\n // -------------------------------------------------------------------------\n // Discovery\n // -------------------------------------------------------------------------\n\n /**\n * Find all existing live regions in the document and start tracking them.\n */\n function discoverExistingRegions(): void {\n // Elements with explicit aria-live\n const ariaLiveElements = document.querySelectorAll('[aria-live]');\n ariaLiveElements.forEach((el) => {\n if (getLiveRegionPoliteness(el) !== null) {\n trackRegion(el);\n }\n });\n\n // Elements with implicit live region roles\n IMPLICIT_LIVE_ROLES.forEach((role) => {\n const roleElements = document.querySelectorAll(`[role=\"${role}\"]`);\n roleElements.forEach((el) => {\n if (!trackedRegions.has(el)) {\n trackRegion(el);\n }\n });\n });\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n function start(): void {\n // Discover existing live regions\n discoverExistingRegions();\n\n // Set up content observer for changes within live regions\n contentObserver = new MutationObserver(handleContentMutations);\n\n // Observe the entire document body for childList and characterData changes\n // in subtrees. We filter by live region ancestry in the handler.\n const body = document.body;\n if (body) {\n contentObserver.observe(body, {\n childList: true,\n characterData: true,\n subtree: true,\n characterDataOldValue: true,\n });\n }\n\n // Set up document observer for detecting new live regions being added\n documentObserver = new MutationObserver(handleDocumentMutations);\n if (body) {\n documentObserver.observe(body, {\n childList: true,\n subtree: true,\n });\n }\n }\n\n function stop(): void {\n if (contentObserver) {\n contentObserver.disconnect();\n contentObserver = null;\n }\n if (documentObserver) {\n documentObserver.disconnect();\n documentObserver = null;\n }\n trackedRegions.clear();\n }\n\n return { start, stop };\n}\n","/**\n * Dialog Observer\n *\n * Observes dialog open/close events on a document and emits DIALOG_OPENED\n * and DIALOG_CLOSED accessibility events. Tracks:\n * - Native `<dialog>` elements gaining/losing the `open` attribute\n * - Elements with role=\"dialog\" or role=\"alertdialog\" being added to the DOM\n * or having aria-modal change\n *\n * Maintains an internal stack of open dialogs for use by the heuristic\n * warnings module.\n *\n * @module runtime/observers/dialog-observer\n */\n\nimport type { AccessibilityEvent, EventTarget as A11yEventTarget } from '../types';\nimport { generateSelector } from '../selector';\n\n// ---------------------------------------------------------------------------\n// Accessible Name Computation (self-contained, dialog-aware)\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the accessible name for a dialog element.\n * Checks aria-label, then aria-labelledby, then title attribute,\n * then falls back to the first heading's textContent within the dialog.\n */\nfunction computeDialogAccessibleName(element: Element, document: Document): string {\n // 1. aria-label takes precedence\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n // 2. aria-labelledby: resolve referenced element(s) text content\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy && labelledBy.trim()) {\n const ids = labelledBy.trim().split(/\\s+/);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = document.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n const combined = parts.join(' ');\n if (combined) {\n return combined;\n }\n }\n\n // 3. title attribute\n const title = element.getAttribute('title');\n if (title && title.trim()) {\n return title.trim();\n }\n\n // 4. First heading within the dialog\n const heading = element.querySelector('h1, h2, h3, h4, h5, h6');\n if (heading && heading.textContent && heading.textContent.trim()) {\n return heading.textContent.trim();\n }\n\n return '';\n}\n\n// ---------------------------------------------------------------------------\n// Role Resolution\n// ---------------------------------------------------------------------------\n\n/**\n * Determine the role of a dialog element.\n * Returns the explicit role attribute value, or 'dialog' for native <dialog>.\n */\nfunction getDialogRole(element: Element): string {\n const explicitRole = element.getAttribute('role');\n if (explicitRole && explicitRole.trim()) {\n return explicitRole.trim();\n }\n\n if (element.tagName.toLowerCase() === 'dialog') {\n return 'dialog';\n }\n\n return 'generic';\n}\n\n// ---------------------------------------------------------------------------\n// Dialog Detection Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Check if an element is a dialog (native <dialog> or role=\"dialog\" / role=\"alertdialog\").\n */\nfunction isDialogElement(element: Element): boolean {\n if (element.tagName.toLowerCase() === 'dialog') {\n return true;\n }\n const role = element.getAttribute('role');\n return role === 'dialog' || role === 'alertdialog';\n}\n\n/**\n * Determine if a dialog is modal.\n * A dialog is modal if:\n * - It's a native <dialog> opened via showModal() (has the `open` attribute and is the top layer)\n * - It has aria-modal=\"true\"\n */\nfunction isDialogModal(element: Element): boolean {\n const ariaModal = element.getAttribute('aria-modal');\n if (ariaModal === 'true') {\n return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Dialog Observer\n// ---------------------------------------------------------------------------\n\n/** Callback type for emitting accessibility events from the observer. */\nexport type DialogEventEmitter = (event: AccessibilityEvent) => void;\n\nexport interface DialogObserverOptions {\n /** The document to observe dialog events on */\n document: Document;\n /** Callback to emit accessibility events */\n onEvent: DialogEventEmitter;\n /** Function to get the current timestamp (ms since session start) */\n getTimestamp: () => number;\n}\n\nexport interface DialogObserver {\n /** Start observing dialog open/close events */\n start(): void;\n /** Stop observing dialog events */\n stop(): void;\n /** Whether the observer is currently active */\n readonly isActive: boolean;\n /** Get the current stack of open dialog names */\n getOpenDialogs(): string[];\n}\n\n/** Internal representation of a tracked open dialog */\ninterface TrackedDialog {\n element: Element;\n name: string;\n selector: string;\n}\n\n/**\n * Creates a DialogObserver that watches for dialog open/close events\n * and emits DIALOG_OPENED / DIALOG_CLOSED accessibility events.\n */\nexport function createDialogObserver(options: DialogObserverOptions): DialogObserver {\n const { document: doc, onEvent, getTimestamp } = options;\n\n let active = false;\n let mutationObserver: MutationObserver | null = null;\n const openDialogStack: TrackedDialog[] = [];\n\n function buildEventTarget(element: Element): A11yEventTarget {\n return {\n role: getDialogRole(element),\n accessibleName: computeDialogAccessibleName(element, doc),\n selector: generateSelector(element),\n };\n }\n\n function emitDialogOpened(element: Element): void {\n const name = computeDialogAccessibleName(element, doc);\n const isModal = isDialogModal(element);\n const target = buildEventTarget(element);\n\n // Add to open dialog stack\n openDialogStack.push({\n element,\n name,\n selector: target.selector,\n });\n\n const a11yEvent: AccessibilityEvent = {\n type: 'DIALOG_OPENED',\n timestamp: getTimestamp(),\n target,\n payload: {\n kind: 'dialog_opened',\n dialogName: name,\n isModal,\n },\n };\n\n onEvent(a11yEvent);\n }\n\n function emitDialogClosed(element: Element): void {\n const name = computeDialogAccessibleName(element, doc);\n const target = buildEventTarget(element);\n\n // Remove from open dialog stack\n const index = openDialogStack.findIndex((d) => d.element === element);\n if (index !== -1) {\n openDialogStack.splice(index, 1);\n }\n\n const a11yEvent: AccessibilityEvent = {\n type: 'DIALOG_CLOSED',\n timestamp: getTimestamp(),\n target,\n payload: {\n kind: 'dialog_closed',\n dialogName: name,\n },\n };\n\n onEvent(a11yEvent);\n }\n\n function isTrackedAsOpen(element: Element): boolean {\n return openDialogStack.some((d) => d.element === element);\n }\n\n function handleMutations(mutations: MutationRecord[]): void {\n if (!active) return;\n\n for (const mutation of mutations) {\n // Handle attribute changes\n if (mutation.type === 'attributes') {\n const target = mutation.target;\n if (!(target instanceof doc.defaultView!.Element)) continue;\n\n // Native <dialog> open attribute change\n if (\n mutation.attributeName === 'open' &&\n target.tagName.toLowerCase() === 'dialog'\n ) {\n if (target.hasAttribute('open')) {\n // Dialog opened\n if (!isTrackedAsOpen(target)) {\n emitDialogOpened(target);\n }\n } else {\n // Dialog closed\n if (isTrackedAsOpen(target)) {\n emitDialogClosed(target);\n }\n }\n }\n\n // aria-modal change on role=\"dialog\" or role=\"alertdialog\"\n if (mutation.attributeName === 'aria-modal' && isDialogElement(target)) {\n // If the dialog is already tracked, the modal status changed but\n // it's still open - we could emit an update, but per spec we just\n // track open/close. The modal status is captured at open time.\n // If it wasn't tracked and now has aria-modal=\"true\", check visibility.\n if (!isTrackedAsOpen(target) && isVisibleDialog(target)) {\n emitDialogOpened(target);\n }\n }\n\n // role attribute change - element might have become a dialog\n if (mutation.attributeName === 'role') {\n const oldRole = mutation.oldValue;\n const newRole = target.getAttribute('role');\n const wasDialog = oldRole === 'dialog' || oldRole === 'alertdialog';\n const isNowDialog = newRole === 'dialog' || newRole === 'alertdialog';\n\n if (!wasDialog && isNowDialog && isVisibleDialog(target)) {\n emitDialogOpened(target);\n } else if (wasDialog && !isNowDialog && isTrackedAsOpen(target)) {\n emitDialogClosed(target);\n }\n }\n }\n\n // Handle added nodes (role=\"dialog\" elements added to the DOM)\n if (mutation.type === 'childList') {\n for (let i = 0; i < mutation.addedNodes.length; i++) {\n const node = mutation.addedNodes[i];\n if (!(node instanceof doc.defaultView!.Element)) continue;\n\n // Check the added node itself\n if (isDialogElement(node) && isVisibleDialog(node)) {\n if (!isTrackedAsOpen(node)) {\n emitDialogOpened(node);\n }\n }\n\n // Check descendants of the added node\n const dialogDescendants = node.querySelectorAll(\n 'dialog[open], [role=\"dialog\"], [role=\"alertdialog\"]'\n );\n for (let j = 0; j < dialogDescendants.length; j++) {\n const dialog = dialogDescendants[j];\n if (isVisibleDialog(dialog) && !isTrackedAsOpen(dialog)) {\n emitDialogOpened(dialog);\n }\n }\n }\n\n // Handle removed nodes - dialogs removed from DOM\n for (let i = 0; i < mutation.removedNodes.length; i++) {\n const node = mutation.removedNodes[i];\n if (!(node instanceof doc.defaultView!.Element)) continue;\n\n // Check the removed node itself\n if (isTrackedAsOpen(node)) {\n emitDialogClosed(node);\n }\n\n // Check descendants of the removed node\n const trackedInRemoved = openDialogStack.filter((d) =>\n node.contains(d.element)\n );\n for (const tracked of trackedInRemoved) {\n emitDialogClosed(tracked.element);\n }\n }\n }\n }\n }\n\n /**\n * Determine if a dialog element is considered \"visible\" / open.\n * - Native <dialog>: must have `open` attribute\n * - ARIA dialog: considered visible when added to DOM (we can't reliably\n * detect CSS visibility in jsdom, so we assume role=\"dialog\" elements\n * in the DOM are intended to be visible)\n */\n function isVisibleDialog(element: Element): boolean {\n if (element.tagName.toLowerCase() === 'dialog') {\n return element.hasAttribute('open');\n }\n // For ARIA dialogs, we treat presence in the DOM as \"visible\"\n // In a real browser, we'd check computed styles, but jsdom doesn't support that reliably\n return true;\n }\n\n return {\n start(): void {\n if (active) return;\n active = true;\n openDialogStack.length = 0;\n\n // Scan existing open dialogs on start\n const existingDialogs = doc.querySelectorAll(\n 'dialog[open], [role=\"dialog\"], [role=\"alertdialog\"]'\n );\n for (let i = 0; i < existingDialogs.length; i++) {\n const dialog = existingDialogs[i];\n if (isVisibleDialog(dialog)) {\n // Track them without emitting events (they were already open before observation)\n openDialogStack.push({\n element: dialog,\n name: computeDialogAccessibleName(dialog, doc),\n selector: generateSelector(dialog),\n });\n }\n }\n\n // Set up MutationObserver\n mutationObserver = new MutationObserver(handleMutations);\n mutationObserver.observe(doc.body || doc.documentElement, {\n attributes: true,\n attributeFilter: ['open', 'role', 'aria-modal'],\n attributeOldValue: true,\n childList: true,\n subtree: true,\n });\n },\n\n stop(): void {\n if (!active) return;\n active = false;\n\n if (mutationObserver) {\n mutationObserver.disconnect();\n mutationObserver = null;\n }\n\n openDialogStack.length = 0;\n },\n\n get isActive(): boolean {\n return active;\n },\n\n getOpenDialogs(): string[] {\n return openDialogStack.map((d) => d.name);\n },\n };\n}\n","/**\n * Runtime Accessibility Engine\n *\n * Coordinates all accessibility observers (focus, mutation, live region, dialog)\n * into a single engine that collects normalized AccessibilityEvents during\n * component interaction. Events are timestamped relative to session start\n * and stored in chronological order.\n *\n * @module runtime/engine\n */\n\nimport type { AccessibilityEvent } from './types';\nimport { createFocusObserver, type FocusObserver } from './observers/focus-observer';\nimport { createMutationObserver, type AccessibilityMutationObserver } from './observers/mutation-observer';\nimport { createLiveRegionObserver, type LiveRegionObserver } from './observers/live-region-observer';\nimport { createDialogObserver, type DialogObserver } from './observers/dialog-observer';\n\n// ---------------------------------------------------------------------------\n// Engine Options\n// ---------------------------------------------------------------------------\n\nexport interface EngineOptions {\n /** Document to observe */\n document: Document;\n /** Whether to enable heuristic warnings (default: true) */\n heuristics?: boolean;\n /** Custom settle time in ms (default: 100) */\n settleTime?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Engine Interface\n// ---------------------------------------------------------------------------\n\nexport interface RuntimeAccessibilityEngine {\n /** Attach observers to the document and begin event collection */\n attach(): void;\n /** Detach all observers and stop collection */\n detach(): void;\n /** Get all collected events since attach (chronological order) */\n getEvents(): AccessibilityEvent[];\n /** Clear collected events without detaching */\n reset(): void;\n /** Whether the engine is currently attached */\n readonly isAttached: boolean;\n /** Expose dialog observer for heuristics module */\n readonly dialogObserver: { getOpenDialogs(): string[] };\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a RuntimeAccessibilityEngine that coordinates all observers\n * and collects accessibility events with monotonically increasing timestamps.\n */\nexport function createEngine(options: EngineOptions): RuntimeAccessibilityEngine {\n const { document: doc } = options;\n\n let attached = false;\n let sessionStart = 0;\n let events: AccessibilityEvent[] = [];\n\n // Timestamp function: returns ms elapsed since session start\n function getTimestamp(): number {\n return Date.now() - sessionStart;\n }\n\n // Shared event collector for focus, mutation, and dialog observers\n function collectEvent(event: AccessibilityEvent): void {\n events.push(event);\n }\n\n // Live region observer has a different callback signature:\n // it emits events without a timestamp, so we wrap to add one\n function collectLiveRegionEvent(event: Omit<AccessibilityEvent, 'timestamp'>): void {\n const fullEvent: AccessibilityEvent = {\n ...event,\n timestamp: getTimestamp(),\n } as AccessibilityEvent;\n events.push(fullEvent);\n }\n\n // Create all observers\n const focusObs: FocusObserver = createFocusObserver({\n document: doc,\n onEvent: collectEvent,\n getTimestamp,\n });\n\n const mutationObs: AccessibilityMutationObserver = createMutationObserver({\n document: doc,\n onEvent: collectEvent,\n getTimestamp,\n });\n\n const liveRegionObs: LiveRegionObserver = createLiveRegionObserver(\n doc,\n collectLiveRegionEvent\n );\n\n const dialogObs: DialogObserver = createDialogObserver({\n document: doc,\n onEvent: collectEvent,\n getTimestamp,\n });\n\n return {\n attach(): void {\n if (attached) return;\n attached = true;\n sessionStart = Date.now();\n events = [];\n\n // Start all observers\n focusObs.start();\n mutationObs.start();\n liveRegionObs.start();\n dialogObs.start();\n },\n\n detach(): void {\n if (!attached) return;\n attached = false;\n\n // Stop all observers\n focusObs.stop();\n mutationObs.stop();\n liveRegionObs.stop();\n dialogObs.stop();\n },\n\n getEvents(): AccessibilityEvent[] {\n // Events are already in chronological order due to single-threaded execution\n return [...events];\n },\n\n reset(): void {\n events = [];\n },\n\n get isAttached(): boolean {\n return attached;\n },\n\n get dialogObserver(): { getOpenDialogs(): string[] } {\n return {\n getOpenDialogs(): string[] {\n return dialogObs.getOpenDialogs();\n },\n };\n },\n };\n}\n","/**\n * Interaction Execution\n *\n * Executes interaction sequences against a document, dispatching proper\n * DOM events (keyboard, mouse, focus) and emitting KEYBOARD_ACTION\n * accessibility events for each action.\n *\n * @module runtime/interactions\n */\n\nimport type { InteractionAction, InteractionSequence, AccessibilityEvent } from './types';\nimport { generateSelector } from './selector';\n\n// ---------------------------------------------------------------------------\n// Key Mappings\n// ---------------------------------------------------------------------------\n\ninterface KeyInfo {\n key: string;\n code: string;\n keyCode: number;\n}\n\nconst KEY_MAP: Record<string, KeyInfo> = {\n Tab: { key: 'Tab', code: 'Tab', keyCode: 9 },\n Escape: { key: 'Escape', code: 'Escape', keyCode: 27 },\n Enter: { key: 'Enter', code: 'Enter', keyCode: 13 },\n ' ': { key: ' ', code: 'Space', keyCode: 32 },\n ArrowUp: { key: 'ArrowUp', code: 'ArrowUp', keyCode: 38 },\n ArrowDown: { key: 'ArrowDown', code: 'ArrowDown', keyCode: 40 },\n ArrowLeft: { key: 'ArrowLeft', code: 'ArrowLeft', keyCode: 37 },\n ArrowRight: { key: 'ArrowRight', code: 'ArrowRight', keyCode: 39 },\n};\n\n// ---------------------------------------------------------------------------\n// Focusable Element Detection\n// ---------------------------------------------------------------------------\n\nconst FOCUSABLE_SELECTOR = [\n 'button:not([disabled])',\n 'a[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ');\n\n/**\n * Get all focusable elements in DOM order, excluding those with tabindex=\"-1\".\n */\nfunction getFocusableElements(document: Document): Element[] {\n return Array.from(document.querySelectorAll(FOCUSABLE_SELECTOR));\n}\n\n// ---------------------------------------------------------------------------\n// Accessible Name and Role (lightweight versions for event target)\n// ---------------------------------------------------------------------------\n\nfunction computeAccessibleName(element: Element, document: Document): string {\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n const labelledBy = element.getAttribute('aria-labelledby');\n if (labelledBy && labelledBy.trim()) {\n const ids = labelledBy.trim().split(/\\s+/);\n const parts: string[] = [];\n for (const id of ids) {\n const referenced = document.getElementById(id);\n if (referenced && referenced.textContent) {\n parts.push(referenced.textContent.trim());\n }\n }\n const combined = parts.join(' ');\n if (combined) return combined;\n }\n\n const textContent = element.textContent;\n if (textContent && textContent.trim()) {\n return textContent.trim();\n }\n\n return '';\n}\n\nfunction getElementRole(element: Element): string {\n const explicitRole = element.getAttribute('role');\n if (explicitRole && explicitRole.trim()) {\n return explicitRole.trim();\n }\n\n const tagName = element.tagName.toLowerCase();\n switch (tagName) {\n case 'button':\n return 'button';\n case 'a':\n return element.hasAttribute('href') ? 'link' : 'generic';\n case 'input': {\n const type = (element.getAttribute('type') || 'text').toLowerCase();\n switch (type) {\n case 'button':\n case 'submit':\n case 'reset':\n case 'image':\n return 'button';\n case 'checkbox':\n return 'checkbox';\n case 'radio':\n return 'radio';\n case 'range':\n return 'slider';\n case 'search':\n return 'searchbox';\n default:\n return 'textbox';\n }\n }\n case 'textarea':\n return 'textbox';\n case 'select':\n return element.hasAttribute('multiple') ? 'listbox' : 'combobox';\n case 'dialog':\n return 'dialog';\n default:\n return 'generic';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Event Target Builder\n// ---------------------------------------------------------------------------\n\nfunction buildEventTarget(element: Element, document: Document) {\n return {\n role: getElementRole(element),\n accessibleName: computeAccessibleName(element, document),\n selector: generateSelector(element),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Keyboard Event Dispatching\n// ---------------------------------------------------------------------------\n\ninterface KeyboardEventOptions {\n key: string;\n code: string;\n keyCode: number;\n shiftKey?: boolean;\n ctrlKey?: boolean;\n altKey?: boolean;\n metaKey?: boolean;\n}\n\n/**\n * Dispatch a full keyboard event sequence (keydown, keypress, keyup)\n * on the currently focused element.\n */\nfunction dispatchKeyboardEvent(\n document: Document,\n options: KeyboardEventOptions\n): void {\n const target = document.activeElement || document.body;\n\n const commonProps = {\n key: options.key,\n code: options.code,\n keyCode: options.keyCode,\n which: options.keyCode,\n shiftKey: options.shiftKey || false,\n ctrlKey: options.ctrlKey || false,\n altKey: options.altKey || false,\n metaKey: options.metaKey || false,\n bubbles: true,\n cancelable: true,\n };\n\n target.dispatchEvent(new KeyboardEvent('keydown', commonProps));\n // keypress is deprecated but still dispatched for compatibility\n // Only dispatch keypress for printable characters\n if (options.key.length === 1) {\n target.dispatchEvent(new KeyboardEvent('keypress', commonProps));\n }\n target.dispatchEvent(new KeyboardEvent('keyup', commonProps));\n}\n\n// ---------------------------------------------------------------------------\n// Key Combo Parsing\n// ---------------------------------------------------------------------------\n\ninterface ParsedCombo {\n key: string;\n modifiers: string[];\n shiftKey: boolean;\n ctrlKey: boolean;\n altKey: boolean;\n metaKey: boolean;\n}\n\n/**\n * Parse a key combination string like \"Control+Shift+A\" into its parts.\n */\nfunction parseKeyCombo(combo: string): ParsedCombo {\n const parts = combo.split('+');\n const modifiers: string[] = [];\n let shiftKey = false;\n let ctrlKey = false;\n let altKey = false;\n let metaKey = false;\n\n // The last part is the key, everything else is a modifier\n const key = parts[parts.length - 1];\n\n for (let i = 0; i < parts.length - 1; i++) {\n const mod = parts[i].toLowerCase();\n switch (mod) {\n case 'shift':\n shiftKey = true;\n modifiers.push('Shift');\n break;\n case 'control':\n case 'ctrl':\n ctrlKey = true;\n modifiers.push('Control');\n break;\n case 'alt':\n altKey = true;\n modifiers.push('Alt');\n break;\n case 'meta':\n case 'cmd':\n case 'command':\n metaKey = true;\n modifiers.push('Meta');\n break;\n }\n }\n\n return { key, modifiers, shiftKey, ctrlKey, altKey, metaKey };\n}\n\n/**\n * Get KeyInfo for a key string. Falls back to generating info from the key name.\n */\nfunction getKeyInfo(key: string): KeyInfo {\n if (KEY_MAP[key]) {\n return KEY_MAP[key];\n }\n // For single character keys\n if (key.length === 1) {\n return {\n key,\n code: `Key${key.toUpperCase()}`,\n keyCode: key.toUpperCase().charCodeAt(0),\n };\n }\n // For other named keys\n return {\n key,\n code: key,\n keyCode: 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Action Executors\n// ---------------------------------------------------------------------------\n\n/**\n * Execute a click action on the element matching the selector.\n * Dispatches mousedown, mouseup, click events, and focuses the element.\n * If the element is not found, emits a WARNING event and continues.\n */\nfunction executeClick(\n selector: string,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const element = document.querySelector(selector);\n\n if (!element) {\n // Emit WARNING for missing element\n const warningEvent: AccessibilityEvent = {\n type: 'WARNING',\n timestamp: getTimestamp(),\n target: {\n role: 'generic',\n accessibleName: '',\n selector: selector,\n },\n payload: {\n kind: 'warning',\n message: `Element not found: ${selector}`,\n },\n };\n onEvent(warningEvent);\n return;\n }\n\n const eventProps = { bubbles: true, cancelable: true };\n\n element.dispatchEvent(new MouseEvent('mousedown', eventProps));\n element.dispatchEvent(new MouseEvent('mouseup', eventProps));\n element.dispatchEvent(new MouseEvent('click', eventProps));\n\n // Focus the element if it's focusable\n if ('focus' in element && typeof (element as HTMLElement).focus === 'function') {\n (element as HTMLElement).focus();\n }\n}\n\n/**\n * Execute a tab action: move focus to the next focusable element.\n */\nfunction executeTab(\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const focusableElements = getFocusableElements(document);\n if (focusableElements.length === 0) return;\n\n const activeElement = document.activeElement;\n let currentIndex = -1;\n\n if (activeElement) {\n currentIndex = focusableElements.indexOf(activeElement);\n }\n\n // Move to next, wrapping around\n const nextIndex = (currentIndex + 1) % focusableElements.length;\n const nextElement = focusableElements[nextIndex] as HTMLElement;\n\n // Dispatch keyboard event on current element\n dispatchKeyboardEvent(document, {\n ...KEY_MAP['Tab'],\n shiftKey: false,\n });\n\n // Move focus\n if (nextElement && typeof nextElement.focus === 'function') {\n nextElement.focus();\n }\n\n // Emit KEYBOARD_ACTION event\n const target = document.activeElement || document.body;\n const keyboardEvent: AccessibilityEvent = {\n type: 'KEYBOARD_ACTION',\n timestamp: getTimestamp(),\n target: buildEventTarget(target as Element, document),\n payload: {\n kind: 'keyboard_action',\n key: 'Tab',\n modifiers: [],\n },\n };\n onEvent(keyboardEvent);\n}\n\n/**\n * Execute a shift+tab action: move focus to the previous focusable element.\n */\nfunction executeShiftTab(\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const focusableElements = getFocusableElements(document);\n if (focusableElements.length === 0) return;\n\n const activeElement = document.activeElement;\n let currentIndex = -1;\n\n if (activeElement) {\n currentIndex = focusableElements.indexOf(activeElement);\n }\n\n // Move to previous, wrapping around\n const prevIndex = currentIndex <= 0 ? focusableElements.length - 1 : currentIndex - 1;\n const prevElement = focusableElements[prevIndex] as HTMLElement;\n\n // Dispatch keyboard event on current element\n dispatchKeyboardEvent(document, {\n ...KEY_MAP['Tab'],\n shiftKey: true,\n });\n\n // Move focus\n if (prevElement && typeof prevElement.focus === 'function') {\n prevElement.focus();\n }\n\n // Emit KEYBOARD_ACTION event\n const target = document.activeElement || document.body;\n const keyboardEvent: AccessibilityEvent = {\n type: 'KEYBOARD_ACTION',\n timestamp: getTimestamp(),\n target: buildEventTarget(target as Element, document),\n payload: {\n kind: 'keyboard_action',\n key: 'Tab',\n modifiers: ['Shift'],\n },\n };\n onEvent(keyboardEvent);\n}\n\n/**\n * Execute a simple keyboard action (escape, enter, space, arrow keys).\n */\nfunction executeKeyAction(\n keyName: string,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const keyInfo = KEY_MAP[keyName];\n if (!keyInfo) return;\n\n dispatchKeyboardEvent(document, {\n ...keyInfo,\n });\n\n // Emit KEYBOARD_ACTION event\n const target = document.activeElement || document.body;\n const keyboardEvent: AccessibilityEvent = {\n type: 'KEYBOARD_ACTION',\n timestamp: getTimestamp(),\n target: buildEventTarget(target as Element, document),\n payload: {\n kind: 'keyboard_action',\n key: keyName,\n modifiers: [],\n },\n };\n onEvent(keyboardEvent);\n}\n\n/**\n * Execute a custom key combination (e.g., \"Control+A\", \"Shift+Tab\").\n */\nfunction executeKeyCombo(\n combo: string,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): void {\n const parsed = parseKeyCombo(combo);\n const keyInfo = getKeyInfo(parsed.key);\n\n dispatchKeyboardEvent(document, {\n ...keyInfo,\n shiftKey: parsed.shiftKey,\n ctrlKey: parsed.ctrlKey,\n altKey: parsed.altKey,\n metaKey: parsed.metaKey,\n });\n\n // Emit KEYBOARD_ACTION event\n const target = document.activeElement || document.body;\n const keyboardEvent: AccessibilityEvent = {\n type: 'KEYBOARD_ACTION',\n timestamp: getTimestamp(),\n target: buildEventTarget(target as Element, document),\n payload: {\n kind: 'keyboard_action',\n key: parsed.key,\n modifiers: parsed.modifiers,\n },\n };\n onEvent(keyboardEvent);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Execute a single interaction action against the document.\n *\n * For keyboard actions, dispatches proper KeyboardEvent sequences (keydown, keypress, keyup).\n * For tab/shiftTab, computes next/previous focusable element and moves focus.\n * Emits KEYBOARD_ACTION events for each keyboard action.\n * Handles missing elements by emitting WARNING events and continuing.\n *\n * Click and wait actions do not emit KEYBOARD_ACTION events.\n */\nexport async function executeAction(\n action: InteractionAction,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number\n): Promise<void> {\n switch (action.type) {\n case 'click':\n executeClick(action.selector, document, onEvent, getTimestamp);\n break;\n\n case 'tab':\n executeTab(document, onEvent, getTimestamp);\n break;\n\n case 'shiftTab':\n executeShiftTab(document, onEvent, getTimestamp);\n break;\n\n case 'escape':\n executeKeyAction('Escape', document, onEvent, getTimestamp);\n break;\n\n case 'enter':\n executeKeyAction('Enter', document, onEvent, getTimestamp);\n break;\n\n case 'space':\n executeKeyAction(' ', document, onEvent, getTimestamp);\n break;\n\n case 'arrowUp':\n executeKeyAction('ArrowUp', document, onEvent, getTimestamp);\n break;\n\n case 'arrowDown':\n executeKeyAction('ArrowDown', document, onEvent, getTimestamp);\n break;\n\n case 'arrowLeft':\n executeKeyAction('ArrowLeft', document, onEvent, getTimestamp);\n break;\n\n case 'arrowRight':\n executeKeyAction('ArrowRight', document, onEvent, getTimestamp);\n break;\n\n case 'key':\n executeKeyCombo(action.combo, document, onEvent, getTimestamp);\n break;\n\n case 'wait':\n // Wait does not emit any events\n await new Promise((resolve) => setTimeout(resolve, action.ms));\n break;\n }\n}\n\n/**\n * Execute an interaction sequence in order, with DOM stability waits between actions.\n *\n * Runs each action sequentially, waiting for `settleTime` milliseconds between actions\n * to allow the DOM to stabilize. This ensures observers can capture resulting changes\n * before the next action fires.\n *\n * @param sequence - The interaction sequence to execute\n * @param document - The target document\n * @param onEvent - Callback to emit accessibility events\n * @param getTimestamp - Function returning current timestamp in ms since session start\n * @param settleTime - Milliseconds to wait between actions for DOM stability (default: 100)\n */\nexport async function executeSequence(\n sequence: InteractionSequence,\n document: Document,\n onEvent: (event: AccessibilityEvent) => void,\n getTimestamp: () => number,\n settleTime: number = 100\n): Promise<void> {\n for (let i = 0; i < sequence.actions.length; i++) {\n const action = sequence.actions[i];\n\n await executeAction(action, document, onEvent, getTimestamp);\n\n // Wait for DOM stability between actions (except after the last action)\n if (i < sequence.actions.length - 1) {\n await new Promise((resolve) => setTimeout(resolve, settleTime));\n }\n }\n}\n","/**\n * Heuristic Warning Analyzer\n *\n * Processes accessibility events one at a time and emits WARNING events\n * when common runtime accessibility anti-patterns are detected. Operates\n * independently of baselines, providing value from the first run.\n *\n * Detected patterns:\n * - Focus not moved into modal dialog within configured timeout (default: 100ms)\n * - Focus escaped modal dialog (focus moved to element outside open dialog)\n * - Rapid announcements (too many in a short window)\n * - Keyboard action with no accessibility response within timeout\n * - Focused element removed from DOM without explicit focus management\n *\n * Uses event timestamps (not real-time timers) for timeout detection,\n * enabling deterministic testing with jsdom.\n *\n * @module runtime/heuristics\n */\n\nimport type {\n AccessibilityEvent,\n EventTarget as A11yEventTarget,\n DialogOpenedPayload,\n WarningPayload,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// Configuration\n// ---------------------------------------------------------------------------\n\n/**\n * Configuration for heuristic warning thresholds.\n */\nexport interface HeuristicConfig {\n /** Time window to detect focus moving into dialog (default: 100ms) */\n dialogFocusTimeout: number;\n /** Time window to detect rapid announcements (default: 500ms) */\n rapidAnnouncementWindow: number;\n /** Threshold for rapid announcement count (default: 3) */\n rapidAnnouncementThreshold: number;\n /** Time window to detect keyboard action response (default: 200ms) */\n keyboardResponseTimeout: number;\n}\n\nconst DEFAULT_CONFIG: HeuristicConfig = {\n dialogFocusTimeout: 100,\n rapidAnnouncementWindow: 500,\n rapidAnnouncementThreshold: 3,\n keyboardResponseTimeout: 200,\n};\n\n// ---------------------------------------------------------------------------\n// Internal State Types\n// ---------------------------------------------------------------------------\n\n/** Tracks a pending dialog focus check */\ninterface PendingDialogFocus {\n /** Selector of the dialog that opened */\n dialogSelector: string;\n /** Name of the dialog for warning messages */\n dialogName: string;\n /** Timestamp when the dialog was opened */\n openedAt: number;\n /** Whether this dialog is modal */\n isModal: boolean;\n /** Whether focus has been moved into the dialog */\n resolved: boolean;\n}\n\n/** Tracks a pending keyboard response check */\ninterface PendingKeyboardResponse {\n /** The keyboard action event that started the check */\n event: AccessibilityEvent;\n /** Timestamp when the keyboard action occurred */\n timestamp: number;\n /** Whether an accessibility response has been received */\n resolved: boolean;\n}\n\n/** Tracks an open dialog for focus escape detection */\ninterface TrackedDialog {\n /** CSS selector of the dialog container */\n selector: string;\n /** Accessible name of the dialog */\n name: string;\n /** Whether this is a modal dialog */\n isModal: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Heuristic Analyzer Interface\n// ---------------------------------------------------------------------------\n\n/**\n * Processes accessibility events and detects runtime anti-patterns.\n */\nexport interface HeuristicAnalyzer {\n /** Process an event and return any warnings it triggers */\n process(event: AccessibilityEvent): AccessibilityEvent[];\n /** Get current open dialog selectors (for focus escape detection) */\n readonly openDialogs: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a heuristic analyzer that processes accessibility events and\n * emits warnings when common anti-patterns are detected.\n *\n * The analyzer uses event timestamps for timeout detection rather than\n * real-time timers, making it deterministic and testable with jsdom.\n */\nexport function createHeuristicAnalyzer(\n config?: Partial<HeuristicConfig>\n): HeuristicAnalyzer {\n const cfg: HeuristicConfig = { ...DEFAULT_CONFIG, ...config };\n\n // Internal state\n const trackedDialogs: TrackedDialog[] = [];\n const pendingDialogFocusChecks: PendingDialogFocus[] = [];\n const pendingKeyboardResponses: PendingKeyboardResponse[] = [];\n const announcementTimestamps: number[] = [];\n\n // Track the last known focused element selector for DOM removal detection\n let lastFocusedSelector: string | null = null;\n\n // ---------------------------------------------------------------------------\n // Helper: Create a WARNING event\n // ---------------------------------------------------------------------------\n\n function createWarning(\n timestamp: number,\n message: string,\n target: A11yEventTarget,\n relatedEvent?: AccessibilityEvent\n ): AccessibilityEvent {\n const payload: WarningPayload = {\n kind: 'warning',\n message,\n relatedEvent,\n };\n\n return {\n type: 'WARNING',\n timestamp,\n target,\n payload,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Check: Dialog focus timeout expired\n // ---------------------------------------------------------------------------\n\n function checkExpiredDialogFocusTimeouts(\n currentTimestamp: number\n ): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n for (let i = pendingDialogFocusChecks.length - 1; i >= 0; i--) {\n const pending = pendingDialogFocusChecks[i];\n if (pending.resolved) continue;\n\n const elapsed = currentTimestamp - pending.openedAt;\n if (elapsed > cfg.dialogFocusTimeout) {\n // Only emit warning for modal dialogs\n if (pending.isModal) {\n warnings.push(\n createWarning(\n currentTimestamp,\n 'Focus was not moved into modal dialog',\n {\n role: 'dialog',\n accessibleName: pending.dialogName,\n selector: pending.dialogSelector,\n }\n )\n );\n }\n // Mark as resolved (expired) to avoid duplicate warnings\n pending.resolved = true;\n }\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Check: Keyboard response timeout expired\n // ---------------------------------------------------------------------------\n\n function checkExpiredKeyboardResponses(\n currentTimestamp: number\n ): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n for (let i = pendingKeyboardResponses.length - 1; i >= 0; i--) {\n const pending = pendingKeyboardResponses[i];\n if (pending.resolved) continue;\n\n const elapsed = currentTimestamp - pending.timestamp;\n if (elapsed > cfg.keyboardResponseTimeout) {\n warnings.push(\n createWarning(\n currentTimestamp,\n 'Keyboard action produced no accessibility response',\n pending.event.target,\n pending.event\n )\n );\n pending.resolved = true;\n }\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Check: Rapid announcements\n // ---------------------------------------------------------------------------\n\n function checkRapidAnnouncements(\n currentTimestamp: number\n ): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n // Remove old timestamps outside the window\n const windowStart = currentTimestamp - cfg.rapidAnnouncementWindow;\n while (announcementTimestamps.length > 0 && announcementTimestamps[0] < windowStart) {\n announcementTimestamps.shift();\n }\n\n // Check if threshold exceeded\n if (announcementTimestamps.length > cfg.rapidAnnouncementThreshold) {\n warnings.push(\n createWarning(\n currentTimestamp,\n 'Rapid announcements detected: assistive technology users may miss content',\n {\n role: 'region',\n accessibleName: '',\n selector: 'body',\n }\n )\n );\n\n // Clear timestamps to avoid repeated warnings for the same burst\n announcementTimestamps.length = 0;\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Check: Focus escape from modal dialog\n // ---------------------------------------------------------------------------\n\n function checkFocusEscape(event: AccessibilityEvent): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n if (event.type !== 'FOCUS_CHANGED') return warnings;\n\n // Only check if there are open modal dialogs\n const modalDialogs = trackedDialogs.filter((d) => d.isModal);\n if (modalDialogs.length === 0) return warnings;\n\n const focusedSelector = event.target.selector;\n\n // Check if the focused element is outside all open modal dialogs\n for (const dialog of modalDialogs) {\n // Focus is outside the dialog if the focused element's selector\n // does not start with/contain the dialog's selector\n if (!isSelectorInside(focusedSelector, dialog.selector)) {\n warnings.push(\n createWarning(\n event.timestamp,\n 'Focus escaped modal dialog',\n event.target,\n event\n )\n );\n break; // One warning is enough\n }\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Check: Focused element removed from DOM\n // ---------------------------------------------------------------------------\n\n function checkFocusedElementRemoved(\n event: AccessibilityEvent\n ): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n // DOM_MUTATION events where the target matches the last focused element\n // indicate the focused element may have been removed\n if (event.type === 'DOM_MUTATION' && lastFocusedSelector !== null) {\n if (event.target.selector === lastFocusedSelector) {\n warnings.push(\n createWarning(\n event.timestamp,\n 'Focused element removed without focus management',\n event.target,\n event\n )\n );\n }\n }\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Selector Containment Check\n // ---------------------------------------------------------------------------\n\n /**\n * Determines if `childSelector` represents an element inside the container\n * identified by `containerSelector`.\n *\n * Uses a simple heuristic: the child selector starts with the container\n * selector followed by a combinator (space, >, ~, +).\n */\n function isSelectorInside(\n childSelector: string,\n containerSelector: string\n ): boolean {\n // Direct match - element IS the container\n if (childSelector === containerSelector) return true;\n\n // Child selector starts with container selector path\n // e.g., container is \"#modal\" and child is \"#modal > .content > button\"\n if (childSelector.startsWith(containerSelector + ' ')) return true;\n if (childSelector.startsWith(containerSelector + ' > ')) return true;\n\n // Handle nth-child and descendant patterns\n // e.g., container is \"body > div:nth-child(2)\" and child is \"body > div:nth-child(2) > button\"\n if (childSelector.startsWith(containerSelector + '>')) return true;\n\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // Event Processing\n // ---------------------------------------------------------------------------\n\n function processEvent(event: AccessibilityEvent): AccessibilityEvent[] {\n const warnings: AccessibilityEvent[] = [];\n\n // First, check for timeouts that may have expired given the current timestamp\n warnings.push(...checkExpiredDialogFocusTimeouts(event.timestamp));\n warnings.push(...checkExpiredKeyboardResponses(event.timestamp));\n\n // Process the event based on its type\n switch (event.type) {\n case 'DIALOG_OPENED': {\n const payload = event.payload as DialogOpenedPayload;\n const dialog: TrackedDialog = {\n selector: event.target.selector,\n name: payload.dialogName,\n isModal: payload.isModal,\n };\n trackedDialogs.push(dialog);\n\n // Set up pending focus check for modal dialogs\n if (payload.isModal) {\n pendingDialogFocusChecks.push({\n dialogSelector: event.target.selector,\n dialogName: payload.dialogName,\n openedAt: event.timestamp,\n isModal: true,\n resolved: false,\n });\n }\n break;\n }\n\n case 'DIALOG_CLOSED': {\n // Remove the dialog from tracked list\n const closedSelector = event.target.selector;\n const idx = trackedDialogs.findIndex(\n (d) => d.selector === closedSelector\n );\n if (idx !== -1) {\n trackedDialogs.splice(idx, 1);\n }\n\n // Resolve any pending focus checks for this dialog\n for (const pending of pendingDialogFocusChecks) {\n if (pending.dialogSelector === closedSelector && !pending.resolved) {\n pending.resolved = true;\n }\n }\n break;\n }\n\n case 'FOCUS_CHANGED': {\n // Resolve pending dialog focus checks if focus moved into dialog\n for (const pending of pendingDialogFocusChecks) {\n if (pending.resolved) continue;\n if (isSelectorInside(event.target.selector, pending.dialogSelector)) {\n pending.resolved = true;\n }\n }\n\n // Resolve pending keyboard responses (focus change is an accessibility response)\n for (const pending of pendingKeyboardResponses) {\n if (!pending.resolved) {\n pending.resolved = true;\n }\n }\n\n // Check for focus escaping modal dialogs\n warnings.push(...checkFocusEscape(event));\n\n // Update last focused element\n lastFocusedSelector = event.target.selector;\n break;\n }\n\n case 'ANNOUNCEMENT': {\n // Track timestamp for rapid announcement detection\n announcementTimestamps.push(event.timestamp);\n\n // Resolve pending keyboard responses (announcement is an accessibility response)\n for (const pending of pendingKeyboardResponses) {\n if (!pending.resolved) {\n pending.resolved = true;\n }\n }\n\n // Check for rapid announcements\n warnings.push(...checkRapidAnnouncements(event.timestamp));\n break;\n }\n\n case 'KEYBOARD_ACTION': {\n // Register pending keyboard response check\n pendingKeyboardResponses.push({\n event,\n timestamp: event.timestamp,\n resolved: false,\n });\n break;\n }\n\n case 'DOM_MUTATION': {\n // Check if the focused element was removed\n warnings.push(...checkFocusedElementRemoved(event));\n\n // DOM mutation is an accessibility response to keyboard action\n for (const pending of pendingKeyboardResponses) {\n if (!pending.resolved) {\n pending.resolved = true;\n }\n }\n break;\n }\n\n case 'STATE_CHANGED':\n case 'ROLE_CHANGED':\n case 'ACCESSIBLE_NAME_CHANGED': {\n // These are all accessibility responses to keyboard actions\n for (const pending of pendingKeyboardResponses) {\n if (!pending.resolved) {\n pending.resolved = true;\n }\n }\n break;\n }\n\n default:\n // WARNING, REGRESSION, and other event types don't trigger heuristics\n break;\n }\n\n // Clean up resolved pending checks to prevent unbounded memory growth\n cleanupResolvedChecks();\n\n return warnings;\n }\n\n // ---------------------------------------------------------------------------\n // Cleanup\n // ---------------------------------------------------------------------------\n\n function cleanupResolvedChecks(): void {\n // Remove resolved pending checks\n for (let i = pendingDialogFocusChecks.length - 1; i >= 0; i--) {\n if (pendingDialogFocusChecks[i].resolved) {\n pendingDialogFocusChecks.splice(i, 1);\n }\n }\n\n for (let i = pendingKeyboardResponses.length - 1; i >= 0; i--) {\n if (pendingKeyboardResponses[i].resolved) {\n pendingKeyboardResponses.splice(i, 1);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Public Interface\n // ---------------------------------------------------------------------------\n\n return {\n process(event: AccessibilityEvent): AccessibilityEvent[] {\n return processEvent(event);\n },\n\n get openDialogs(): string[] {\n return trackedDialogs.map((d) => d.selector);\n },\n };\n}\n","/**\n * Single source of truth for the package version.\n *\n * The value is injected at build/test time via the `__SPEAKABLE_VERSION__`\n * define, which reads it from package.json:\n * - production bundles: defined in tsup.config.ts (all entries)\n * - the test suite: defined in vitest.config.ts\n *\n * This keeps runtime-reported versions (timeline metadata, baseline files, the\n * browser bundle) in lockstep with the published version, with no hardcoded\n * strings to drift. This module is browser-safe: it has no Node-only imports,\n * so it can be bundled into the browser/IIFE build.\n */\n\ndeclare const __SPEAKABLE_VERSION__: string | undefined;\n\n/** The resolved package version (e.g. \"1.7.0\"), or \"dev\" if the define is absent. */\nexport const SPEAKABLE_VERSION: string =\n typeof __SPEAKABLE_VERSION__ !== 'undefined' && __SPEAKABLE_VERSION__\n ? __SPEAKABLE_VERSION__\n : 'dev';\n","/**\n * Timeline Generator\n *\n * Orchestrates interaction sessions by coordinating the RuntimeAccessibilityEngine\n * with interaction execution and heuristic analysis. Produces complete\n * AccessibilityTimeline objects containing ordered events, warnings, and\n * session metadata.\n *\n * @module runtime/timeline-generator\n */\n\nimport type {\n AccessibilityEvent,\n AccessibilityTimeline,\n InteractionSequence,\n TimelineMetadata,\n} from './types';\nimport { createEngine, type RuntimeAccessibilityEngine } from './engine';\nimport { executeSequence } from './interactions';\nimport { createHeuristicAnalyzer, type HeuristicAnalyzer } from './heuristics';\nimport { SPEAKABLE_VERSION } from '../version.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst TIMELINE_FORMAT_VERSION = '1.0';\nconst DEFAULT_SETTLE_PERIOD = 500;\nconst DEFAULT_LOAD_TIMEOUT = 10000;\nconst DOM_STABILITY_WAIT = 100;\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/**\n * Configuration options for creating a TimelineGenerator.\n */\nexport interface TimelineGeneratorOptions {\n /** Document or iframe to attach to */\n document: Document;\n /** Component name for metadata */\n componentName: string;\n /** Story or variant name for metadata */\n storyName?: string;\n /** Settle period after last action (default: 500ms) */\n settlePeriod?: number;\n /** Maximum wait for document load (default: 10000ms) */\n loadTimeout?: number;\n /** Enable heuristic warnings (default: true) */\n heuristics?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Timeline Generator Interface\n// ---------------------------------------------------------------------------\n\n/**\n * Orchestrates an interaction session and produces an AccessibilityTimeline.\n */\nexport interface TimelineGenerator {\n /** Execute an interaction sequence and produce a timeline */\n capture(sequence: InteractionSequence): Promise<AccessibilityTimeline>;\n /** Abort an in-progress capture */\n abort(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a TimelineGenerator that coordinates the engine, interaction\n * execution, and heuristic analysis to produce accessibility timelines.\n *\n * Usage:\n * ```ts\n * const generator = createTimelineGenerator({\n * document: myDocument,\n * componentName: 'LoginForm',\n * storyName: 'Default',\n * });\n *\n * const timeline = await generator.capture({\n * description: 'Tab through form fields',\n * actions: [{ type: 'tab' }, { type: 'tab' }, { type: 'enter' }],\n * });\n * ```\n */\nexport function createTimelineGenerator(\n options: TimelineGeneratorOptions\n): TimelineGenerator {\n const {\n document: doc,\n componentName,\n storyName,\n settlePeriod = DEFAULT_SETTLE_PERIOD,\n loadTimeout = DEFAULT_LOAD_TIMEOUT,\n heuristics: enableHeuristics = true,\n } = options;\n\n let aborted = false;\n let currentEngine: RuntimeAccessibilityEngine | null = null;\n\n return {\n async capture(sequence: InteractionSequence): Promise<AccessibilityTimeline> {\n aborted = false;\n\n // Wait for document to be ready (body must exist)\n await waitForDocumentReady(doc, loadTimeout);\n\n if (aborted) {\n return buildAbortedTimeline(componentName, storyName, sequence);\n }\n\n // Create engine and attach\n const engine = createEngine({ document: doc });\n currentEngine = engine;\n\n // Create heuristic analyzer if enabled\n const heuristicAnalyzer: HeuristicAnalyzer | null = enableHeuristics\n ? createHeuristicAnalyzer()\n : null;\n\n // Collect interaction-emitted events (KEYBOARD_ACTION, WARNINGs from missing elements)\n // These are not captured by the engine's observers.\n const interactionEvents: AccessibilityEvent[] = [];\n\n const sessionStart = Date.now();\n engine.attach();\n\n if (aborted) {\n engine.detach();\n currentEngine = null;\n return buildAbortedTimeline(componentName, storyName, sequence);\n }\n\n // Timestamp function for interactions\n function getTimestamp(): number {\n return Date.now() - sessionStart;\n }\n\n // Execute the interaction sequence with DOM stability waits\n await executeSequence(\n sequence,\n doc,\n (event: AccessibilityEvent) => {\n interactionEvents.push(event);\n },\n getTimestamp,\n DOM_STABILITY_WAIT\n );\n\n if (aborted) {\n engine.detach();\n currentEngine = null;\n return buildAbortedTimeline(componentName, storyName, sequence);\n }\n\n // Wait the settle period for trailing async events\n await delay(settlePeriod);\n\n // Detach engine and finalize\n engine.detach();\n currentEngine = null;\n\n const duration = Date.now() - sessionStart;\n\n // Merge engine events with interaction events, sorted by timestamp\n const engineEvents = engine.getEvents();\n const allEvents = mergeEvents(engineEvents, interactionEvents);\n\n // Run heuristic analysis on all events if enabled\n if (heuristicAnalyzer) {\n const heuristicWarnings: AccessibilityEvent[] = [];\n for (const event of allEvents) {\n const warnings = heuristicAnalyzer.process(event);\n heuristicWarnings.push(...warnings);\n }\n // Add heuristic warnings to the event stream\n for (const warning of heuristicWarnings) {\n allEvents.push(warning);\n }\n // Re-sort after adding heuristic warnings\n allEvents.sort((a, b) => a.timestamp - b.timestamp);\n }\n\n // Extract all WARNING events for the warnings array\n const allWarnings = allEvents.filter((e) => e.type === 'WARNING');\n\n // Build metadata\n const metadata: TimelineMetadata = {\n capturedAt: new Date().toISOString(),\n speakableVersion: SPEAKABLE_VERSION,\n sourceUrl: getSourceUrl(doc),\n userAgent: getUserAgent(),\n };\n\n // Build and return the AccessibilityTimeline\n const timeline: AccessibilityTimeline = {\n version: TIMELINE_FORMAT_VERSION,\n component: componentName,\n story: storyName || null,\n interactionSequence: sequence.description,\n duration,\n events: allEvents,\n warnings: allWarnings,\n metadata,\n };\n\n return timeline;\n },\n\n abort(): void {\n aborted = true;\n if (currentEngine && currentEngine.isAttached) {\n currentEngine.detach();\n currentEngine = null;\n }\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Wait for the document body to be available, with a timeout.\n * If the document already has a body, resolves immediately.\n */\nasync function waitForDocumentReady(\n doc: Document,\n timeout: number\n): Promise<void> {\n if (doc.body) return;\n\n return new Promise<void>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(\n new Error(\n `Document load timeout (${timeout}ms): ${getSourceUrl(doc)}`\n )\n );\n }, timeout);\n\n // Poll for body availability\n const interval = setInterval(() => {\n if (doc.body) {\n clearTimeout(timeoutId);\n clearInterval(interval);\n resolve();\n }\n }, 50);\n });\n}\n\n/**\n * Merge two event arrays into a single sorted array by timestamp.\n */\nfunction mergeEvents(\n engineEvents: AccessibilityEvent[],\n interactionEvents: AccessibilityEvent[]\n): AccessibilityEvent[] {\n const all = [...engineEvents, ...interactionEvents];\n all.sort((a, b) => a.timestamp - b.timestamp);\n return all;\n}\n\n/**\n * Get the source URL from a document, falling back to 'local'.\n */\nfunction getSourceUrl(doc: Document): string {\n try {\n const url = doc.URL;\n if (url && url !== 'about:blank' && url !== '') {\n return url;\n }\n } catch {\n // Ignore errors accessing URL\n }\n return 'local';\n}\n\n/**\n * Get the user agent string, defaulting to 'jsdom' for Node.js environments.\n */\nfunction getUserAgent(): string {\n try {\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return navigator.userAgent;\n }\n } catch {\n // Ignore errors\n }\n return 'jsdom';\n}\n\n/**\n * Simple promise-based delay.\n */\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Build an empty timeline for aborted captures.\n */\nfunction buildAbortedTimeline(\n componentName: string,\n storyName: string | undefined,\n sequence: InteractionSequence\n): AccessibilityTimeline {\n return {\n version: TIMELINE_FORMAT_VERSION,\n component: componentName,\n story: storyName || null,\n interactionSequence: sequence.description,\n duration: 0,\n events: [],\n warnings: [],\n metadata: {\n capturedAt: new Date().toISOString(),\n speakableVersion: SPEAKABLE_VERSION,\n sourceUrl: 'local',\n userAgent: getUserAgent(),\n },\n };\n}\n","/**\n * Built-in Interaction Patterns\n *\n * Provides pre-defined interaction sequences for common ARIA widget patterns.\n * Each pattern exercises standard keyboard interaction behavior as defined by\n * the WAI-ARIA Authoring Practices. Patterns use configurable selectors that\n * can be overridden to match component-specific markup.\n *\n * @module runtime/patterns\n */\n\nimport type { InteractionSequence, InteractionAction } from './types';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Optional map of CSS selectors to override defaults for built-in patterns.\n *\n * - `trigger` — element that opens/activates the widget\n * - `container` — wrapper/container element for the widget\n * - `content` — the content region within the widget\n * - `items` — individual items within the widget (options, tabs, etc.)\n * - `input` — text input element within the widget\n */\nexport interface PatternSelectorMap {\n trigger?: string;\n container?: string;\n content?: string;\n items?: string;\n input?: string;\n}\n\n/**\n * Names of built-in interaction patterns.\n */\nexport type BuiltinPatternName = 'modal-dialog' | 'combobox' | 'tabs' | 'accordion';\n\n// ---------------------------------------------------------------------------\n// Default Selectors\n// ---------------------------------------------------------------------------\n\nconst MODAL_DIALOG_DEFAULTS: Required<Pick<PatternSelectorMap, 'trigger' | 'container'>> = {\n trigger: 'button',\n container: '[role=\"dialog\"], dialog',\n};\n\nconst COMBOBOX_DEFAULTS: Required<Pick<PatternSelectorMap, 'input' | 'items'>> = {\n input: '[role=\"combobox\"], input[type=\"text\"]',\n items: '[role=\"option\"]',\n};\n\nconst TABS_DEFAULTS: Required<Pick<PatternSelectorMap, 'container' | 'items'>> = {\n container: '[role=\"tablist\"]',\n items: '[role=\"tab\"]',\n};\n\nconst ACCORDION_DEFAULTS: Required<Pick<PatternSelectorMap, 'trigger'>> = {\n trigger: 'button[aria-expanded]',\n};\n\n// ---------------------------------------------------------------------------\n// Pattern Builders\n// ---------------------------------------------------------------------------\n\n/**\n * Modal dialog pattern:\n * 1. Click trigger to open dialog\n * 2. Tab through dialog content (verify focus is in dialog)\n * 3. Tab through more content\n * 4. Press Escape to close\n * 5. Verify focus returns to trigger (implicit via focus observer)\n */\nfunction buildModalDialogPattern(selectors?: PatternSelectorMap): InteractionSequence {\n const trigger = selectors?.trigger ?? MODAL_DIALOG_DEFAULTS.trigger;\n\n const actions: InteractionAction[] = [\n { type: 'click', selector: trigger },\n { type: 'tab' },\n { type: 'tab' },\n { type: 'tab' },\n { type: 'escape' },\n ];\n\n return {\n description:\n 'Modal dialog: click trigger to open, tab through dialog content, press Escape to close, verify focus returns to trigger',\n actions,\n };\n}\n\n/**\n * Combobox pattern:\n * 1. Click/focus the combobox input\n * 2. Type to filter (simulated via key events)\n * 3. Arrow down through options\n * 4. Arrow down again\n * 5. Enter to select\n */\nfunction buildComboboxPattern(selectors?: PatternSelectorMap): InteractionSequence {\n const input = selectors?.input ?? COMBOBOX_DEFAULTS.input;\n\n const actions: InteractionAction[] = [\n { type: 'click', selector: input },\n { type: 'key', combo: 'a' },\n { type: 'arrowDown' },\n { type: 'arrowDown' },\n { type: 'enter' },\n ];\n\n return {\n description:\n 'Combobox: focus input, type to filter, navigate options with arrow keys, select with Enter',\n actions,\n };\n}\n\n/**\n * Tabs pattern:\n * 1. Click/focus the tablist container\n * 2. Arrow right to next tab\n * 3. Arrow right to next tab\n * 4. Enter to activate\n * 5. Arrow left to previous tab\n * 6. Space to activate\n */\nfunction buildTabsPattern(selectors?: PatternSelectorMap): InteractionSequence {\n const container = selectors?.container ?? TABS_DEFAULTS.container;\n\n const actions: InteractionAction[] = [\n { type: 'click', selector: container },\n { type: 'arrowRight' },\n { type: 'arrowRight' },\n { type: 'enter' },\n { type: 'arrowLeft' },\n { type: 'space' },\n ];\n\n return {\n description:\n 'Tabs: focus tablist, navigate between tabs with arrow keys, activate with Enter/Space',\n actions,\n };\n}\n\n/**\n * Accordion pattern:\n * 1. Click/focus the first accordion header\n * 2. Enter to toggle expanded/collapsed\n * 3. Arrow down to next header\n * 4. Space to toggle\n * 5. Arrow down to next header\n * 6. Enter to toggle\n */\nfunction buildAccordionPattern(selectors?: PatternSelectorMap): InteractionSequence {\n const trigger = selectors?.trigger ?? ACCORDION_DEFAULTS.trigger;\n\n const actions: InteractionAction[] = [\n { type: 'click', selector: trigger },\n { type: 'enter' },\n { type: 'arrowDown' },\n { type: 'space' },\n { type: 'arrowDown' },\n { type: 'enter' },\n ];\n\n return {\n description:\n 'Accordion: focus header, toggle with Enter/Space, navigate between headers with arrow keys',\n actions,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Get a built-in interaction pattern by name.\n *\n * Each pattern returns an InteractionSequence with a descriptive name and the\n * appropriate actions for testing common ARIA widget patterns. Optional selectors\n * can override the defaults used to locate trigger, container, and content elements.\n *\n * Default selectors:\n * - modal-dialog: trigger = 'button', container = '[role=\"dialog\"], dialog'\n * - combobox: input = '[role=\"combobox\"], input[type=\"text\"]', items = '[role=\"option\"]'\n * - tabs: container = '[role=\"tablist\"]', items = '[role=\"tab\"]'\n * - accordion: trigger = 'button[aria-expanded]'\n *\n * @param name - The built-in pattern name\n * @param selectors - Optional CSS selectors to override defaults\n * @returns An InteractionSequence representing the pattern\n */\nexport function getBuiltinPattern(\n name: BuiltinPatternName,\n selectors?: PatternSelectorMap\n): InteractionSequence {\n switch (name) {\n case 'modal-dialog':\n return buildModalDialogPattern(selectors);\n case 'combobox':\n return buildComboboxPattern(selectors);\n case 'tabs':\n return buildTabsPattern(selectors);\n case 'accordion':\n return buildAccordionPattern(selectors);\n }\n}\n","/**\n * Deterministic serialization and deserialization for Runtime Accessibility\n * Timeline types.\n *\n * All serializers produce JSON with recursively sorted keys and 2-space\n * indentation, guaranteeing:\n * - Byte-identical output for equivalent inputs (determinism)\n * - Round-trip integrity (serialize → deserialize → serialize = identical)\n * - Stable version-control diffs\n */\n\nimport type {\n AccessibilityEvent,\n AccessibilityTimeline,\n EventPayload,\n EventTarget,\n EventType,\n InteractionAction,\n InteractionSequence,\n TimelineMetadata,\n} from './types.js';\n\n// ---------------------------------------------------------------------------\n// Validation constants\n// ---------------------------------------------------------------------------\n\nconst VALID_EVENT_TYPES: ReadonlySet<string> = new Set<EventType>([\n 'FOCUS_CHANGED',\n 'ANNOUNCEMENT',\n 'DOM_MUTATION',\n 'ROLE_CHANGED',\n 'ACCESSIBLE_NAME_CHANGED',\n 'STATE_CHANGED',\n 'KEYBOARD_ACTION',\n 'DIALOG_OPENED',\n 'DIALOG_CLOSED',\n 'WARNING',\n 'REGRESSION',\n]);\n\nconst VALID_PAYLOAD_KINDS: ReadonlySet<string> = new Set([\n 'focus_changed',\n 'announcement',\n 'role_changed',\n 'accessible_name_changed',\n 'state_changed',\n 'dialog_opened',\n 'dialog_closed',\n 'keyboard_action',\n 'warning',\n]);\n\nconst VALID_ACTION_TYPES: ReadonlySet<string> = new Set([\n 'click',\n 'tab',\n 'shiftTab',\n 'escape',\n 'enter',\n 'space',\n 'arrowUp',\n 'arrowDown',\n 'arrowLeft',\n 'arrowRight',\n 'key',\n 'wait',\n]);\n\n// ---------------------------------------------------------------------------\n// Recursive key sorting\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively sorts all object keys in a value. Arrays are traversed but\n * their element order is preserved. Primitives pass through unchanged.\n */\nfunction sortKeysDeep<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map(sortKeysDeep) as unknown as T;\n }\n\n if (typeof value === 'object') {\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(value as Record<string, unknown>).sort();\n for (const key of keys) {\n sorted[key] = sortKeysDeep((value as Record<string, unknown>)[key]);\n }\n return sorted as T;\n }\n\n return value;\n}\n\n// ---------------------------------------------------------------------------\n// Event Serialization\n// ---------------------------------------------------------------------------\n\n/**\n * Serializes an AccessibilityEvent to deterministic JSON with sorted keys\n * and 2-space indentation.\n *\n * @param event - The accessibility event to serialize\n * @returns Deterministic JSON string\n */\nexport function serializeEvent(event: AccessibilityEvent): string {\n const sorted = sortKeysDeep(event);\n return JSON.stringify(sorted, null, 2);\n}\n\n/**\n * Deserializes a JSON string into a validated AccessibilityEvent.\n *\n * @param json - JSON string to parse\n * @returns Validated AccessibilityEvent\n * @throws Error if the JSON is invalid or does not conform to the event schema\n */\nexport function deserializeEvent(json: string): AccessibilityEvent {\n const parsed = JSON.parse(json);\n validateEvent(parsed);\n return parsed as AccessibilityEvent;\n}\n\n// ---------------------------------------------------------------------------\n// Timeline Serialization\n// ---------------------------------------------------------------------------\n\n/**\n * Serializes an AccessibilityTimeline to deterministic JSON with sorted keys\n * and 2-space indentation.\n *\n * @param timeline - The accessibility timeline to serialize\n * @returns Deterministic JSON string\n */\nexport function serializeTimeline(timeline: AccessibilityTimeline): string {\n const sorted = sortKeysDeep(timeline);\n return JSON.stringify(sorted, null, 2);\n}\n\n/**\n * Deserializes a JSON string into a validated AccessibilityTimeline.\n *\n * @param json - JSON string to parse\n * @returns Validated AccessibilityTimeline\n * @throws Error if the JSON is invalid or does not conform to the timeline schema\n */\nexport function deserializeTimeline(json: string): AccessibilityTimeline {\n const parsed = JSON.parse(json);\n validateTimeline(parsed);\n return parsed as AccessibilityTimeline;\n}\n\n// ---------------------------------------------------------------------------\n// InteractionSequence Serialization\n// ---------------------------------------------------------------------------\n\n/**\n * Serializes an InteractionSequence to deterministic JSON with sorted keys\n * and 2-space indentation.\n *\n * @param seq - The interaction sequence to serialize\n * @returns Deterministic JSON string\n */\nexport function serializeInteractionSequence(seq: InteractionSequence): string {\n const sorted = sortKeysDeep(seq);\n return JSON.stringify(sorted, null, 2);\n}\n\n/**\n * Deserializes a JSON string into a validated InteractionSequence.\n *\n * @param json - JSON string to parse\n * @returns Validated InteractionSequence\n * @throws Error if the JSON is invalid or does not conform to the interaction schema\n */\nexport function deserializeInteractionSequence(json: string): InteractionSequence {\n const parsed = JSON.parse(json);\n validateInteractionSequence(parsed);\n return parsed as InteractionSequence;\n}\n\n// ---------------------------------------------------------------------------\n// Deep Equality\n// ---------------------------------------------------------------------------\n\n/**\n * Checks whether two AccessibilityTimelines are deeply equal by comparing\n * their deterministic serializations. Because serialization sorts keys\n * recursively, structurally equivalent timelines produce identical strings.\n *\n * @param a - First timeline\n * @param b - Second timeline\n * @returns true if timelines are equivalent\n */\nexport function timelinesEqual(\n a: AccessibilityTimeline,\n b: AccessibilityTimeline,\n): boolean {\n return serializeTimeline(a) === serializeTimeline(b);\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\nfunction validateEvent(obj: unknown): asserts obj is AccessibilityEvent {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('Event must be a non-null object');\n }\n\n const event = obj as Record<string, unknown>;\n\n // type\n if (typeof event.type !== 'string' || !VALID_EVENT_TYPES.has(event.type)) {\n throw new Error(\n `Event \"type\" must be one of: ${[...VALID_EVENT_TYPES].join(', ')}. Got: ${String(event.type)}`,\n );\n }\n\n // timestamp\n if (typeof event.timestamp !== 'number' || !Number.isFinite(event.timestamp)) {\n throw new Error('Event \"timestamp\" must be a finite number');\n }\n\n // target\n validateEventTarget(event.target, 'Event \"target\"');\n\n // payload\n validatePayload(event.payload);\n}\n\nfunction validateEventTarget(obj: unknown, label: string): asserts obj is EventTarget {\n if (obj === null || typeof obj !== 'object') {\n throw new Error(`${label} must be a non-null object`);\n }\n\n const target = obj as Record<string, unknown>;\n\n if (typeof target.role !== 'string') {\n throw new Error(`${label}.role must be a string`);\n }\n if (typeof target.accessibleName !== 'string') {\n throw new Error(`${label}.accessibleName must be a string`);\n }\n if (typeof target.selector !== 'string') {\n throw new Error(`${label}.selector must be a string`);\n }\n}\n\nfunction validatePayload(obj: unknown): asserts obj is EventPayload {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('Event \"payload\" must be a non-null object');\n }\n\n const payload = obj as Record<string, unknown>;\n\n if (typeof payload.kind !== 'string' || !VALID_PAYLOAD_KINDS.has(payload.kind)) {\n throw new Error(\n `Payload \"kind\" must be one of: ${[...VALID_PAYLOAD_KINDS].join(', ')}. Got: ${String(payload.kind)}`,\n );\n }\n\n // Type-specific validation\n switch (payload.kind) {\n case 'focus_changed':\n if (payload.previousTarget !== null) {\n validateEventTarget(payload.previousTarget, 'FocusChangedPayload.previousTarget');\n }\n break;\n\n case 'announcement':\n if (payload.politeness !== 'polite' && payload.politeness !== 'assertive') {\n throw new Error('AnnouncementPayload.politeness must be \"polite\" or \"assertive\"');\n }\n if (typeof payload.text !== 'string') {\n throw new Error('AnnouncementPayload.text must be a string');\n }\n break;\n\n case 'role_changed':\n if (typeof payload.previousRole !== 'string') {\n throw new Error('RoleChangedPayload.previousRole must be a string');\n }\n if (typeof payload.newRole !== 'string') {\n throw new Error('RoleChangedPayload.newRole must be a string');\n }\n break;\n\n case 'accessible_name_changed':\n if (typeof payload.previousName !== 'string') {\n throw new Error('AccessibleNameChangedPayload.previousName must be a string');\n }\n if (typeof payload.newName !== 'string') {\n throw new Error('AccessibleNameChangedPayload.newName must be a string');\n }\n break;\n\n case 'state_changed':\n if (typeof payload.attribute !== 'string') {\n throw new Error('StateChangedPayload.attribute must be a string');\n }\n validateStateValue(payload.previousValue, 'StateChangedPayload.previousValue');\n validateStateValue(payload.newValue, 'StateChangedPayload.newValue');\n break;\n\n case 'dialog_opened':\n if (typeof payload.dialogName !== 'string') {\n throw new Error('DialogOpenedPayload.dialogName must be a string');\n }\n if (typeof payload.isModal !== 'boolean') {\n throw new Error('DialogOpenedPayload.isModal must be a boolean');\n }\n break;\n\n case 'dialog_closed':\n if (typeof payload.dialogName !== 'string') {\n throw new Error('DialogClosedPayload.dialogName must be a string');\n }\n break;\n\n case 'keyboard_action':\n if (typeof payload.key !== 'string') {\n throw new Error('KeyboardActionPayload.key must be a string');\n }\n if (!Array.isArray(payload.modifiers)) {\n throw new Error('KeyboardActionPayload.modifiers must be an array');\n }\n for (const mod of payload.modifiers) {\n if (typeof mod !== 'string') {\n throw new Error('KeyboardActionPayload.modifiers must contain only strings');\n }\n }\n break;\n\n case 'warning':\n if (typeof payload.message !== 'string') {\n throw new Error('WarningPayload.message must be a string');\n }\n if (payload.relatedEvent !== undefined && payload.relatedEvent !== null) {\n validateEvent(payload.relatedEvent);\n }\n break;\n }\n}\n\nfunction validateStateValue(value: unknown, label: string): void {\n if (value !== null && typeof value !== 'string' && typeof value !== 'boolean') {\n throw new Error(`${label} must be a string, boolean, or null`);\n }\n}\n\nfunction validateTimeline(obj: unknown): asserts obj is AccessibilityTimeline {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('Timeline must be a non-null object');\n }\n\n const timeline = obj as Record<string, unknown>;\n\n // version\n if (typeof timeline.version !== 'string') {\n throw new Error('Timeline \"version\" must be a string');\n }\n\n // component\n if (typeof timeline.component !== 'string') {\n throw new Error('Timeline \"component\" must be a string');\n }\n\n // story (string | null)\n if (timeline.story !== null && typeof timeline.story !== 'string') {\n throw new Error('Timeline \"story\" must be a string or null');\n }\n\n // interactionSequence\n if (typeof timeline.interactionSequence !== 'string') {\n throw new Error('Timeline \"interactionSequence\" must be a string');\n }\n\n // duration\n if (typeof timeline.duration !== 'number' || !Number.isFinite(timeline.duration)) {\n throw new Error('Timeline \"duration\" must be a finite number');\n }\n\n // events\n if (!Array.isArray(timeline.events)) {\n throw new Error('Timeline \"events\" must be an array');\n }\n for (let i = 0; i < timeline.events.length; i++) {\n try {\n validateEvent(timeline.events[i]);\n } catch (err) {\n throw new Error(\n `Timeline events[${i}]: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // warnings\n if (!Array.isArray(timeline.warnings)) {\n throw new Error('Timeline \"warnings\" must be an array');\n }\n for (let i = 0; i < timeline.warnings.length; i++) {\n try {\n validateEvent(timeline.warnings[i]);\n } catch (err) {\n throw new Error(\n `Timeline warnings[${i}]: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // metadata\n validateTimelineMetadata(timeline.metadata);\n}\n\nfunction validateTimelineMetadata(obj: unknown): asserts obj is TimelineMetadata {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('Timeline \"metadata\" must be a non-null object');\n }\n\n const meta = obj as Record<string, unknown>;\n\n if (typeof meta.capturedAt !== 'string') {\n throw new Error('Timeline metadata.capturedAt must be a string');\n }\n if (typeof meta.speakableVersion !== 'string') {\n throw new Error('Timeline metadata.speakableVersion must be a string');\n }\n if (typeof meta.sourceUrl !== 'string') {\n throw new Error('Timeline metadata.sourceUrl must be a string');\n }\n if (typeof meta.userAgent !== 'string') {\n throw new Error('Timeline metadata.userAgent must be a string');\n }\n}\n\nfunction validateInteractionSequence(obj: unknown): asserts obj is InteractionSequence {\n if (obj === null || typeof obj !== 'object') {\n throw new Error('InteractionSequence must be a non-null object');\n }\n\n const seq = obj as Record<string, unknown>;\n\n if (typeof seq.description !== 'string') {\n throw new Error('InteractionSequence \"description\" must be a string');\n }\n\n if (!Array.isArray(seq.actions)) {\n throw new Error('InteractionSequence \"actions\" must be an array');\n }\n\n for (let i = 0; i < seq.actions.length; i++) {\n validateAction(seq.actions[i], i);\n }\n}\n\nfunction validateAction(obj: unknown, index: number): asserts obj is InteractionAction {\n if (obj === null || typeof obj !== 'object') {\n throw new Error(`InteractionSequence actions[${index}] must be a non-null object`);\n }\n\n const action = obj as Record<string, unknown>;\n\n if (typeof action.type !== 'string' || !VALID_ACTION_TYPES.has(action.type)) {\n throw new Error(\n `InteractionSequence actions[${index}].type must be one of: ${[...VALID_ACTION_TYPES].join(', ')}. Got: ${String(action.type)}`,\n );\n }\n\n switch (action.type) {\n case 'click':\n if (typeof action.selector !== 'string') {\n throw new Error(\n `InteractionSequence actions[${index}].selector must be a string for click actions`,\n );\n }\n break;\n\n case 'key':\n if (typeof action.combo !== 'string') {\n throw new Error(\n `InteractionSequence actions[${index}].combo must be a string for key actions`,\n );\n }\n break;\n\n case 'wait':\n if (typeof action.ms !== 'number' || !Number.isFinite(action.ms)) {\n throw new Error(\n `InteractionSequence actions[${index}].ms must be a finite number for wait actions`,\n );\n }\n break;\n }\n}\n","/**\n * Behavior Diff Engine\n *\n * Compares two Accessibility Timelines and produces a BehaviorDiffReport\n * describing added, removed, and modified events. Events are matched by\n * type + target selector. Timestamp differences alone do not count as\n * modifications.\n */\n\nimport type { AccessibilityEvent, AccessibilityTimeline } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Public Interfaces\n// ---------------------------------------------------------------------------\n\n/**\n * A single entry in the diff report representing one difference between\n * baseline and current timelines.\n */\nexport interface DiffEntry {\n /** The event from the current timeline (for added/modified) or baseline (for removed) */\n event: AccessibilityEvent;\n /** The corresponding event from the other timeline (for modified entries) */\n previousEvent?: AccessibilityEvent;\n /** Human-readable description of the difference */\n message: string;\n}\n\n/**\n * Structured summary of differences between two Accessibility Timelines.\n */\nexport interface BehaviorDiffReport {\n baseline: { totalEvents: number };\n current: { totalEvents: number };\n /** Events present in current but not in baseline */\n added: DiffEntry[];\n /** Events present in baseline but not in current */\n removed: DiffEntry[];\n /** Events present in both but with different payloads */\n modified: DiffEntry[];\n /** Aggregate counts (must equal array lengths exactly) */\n summary: {\n totalBaseline: number;\n totalCurrent: number;\n added: number;\n removed: number;\n modified: number;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internal Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a matching key for an event based on type and target selector.\n * This is the primary key used to correlate events across timelines.\n */\nfunction matchingKey(event: AccessibilityEvent): string {\n return `${event.type}::${event.target.selector}`;\n}\n\n/**\n * Compare two event payloads for equality, ignoring the timestamp field.\n * Returns true if payloads are structurally identical.\n */\nfunction payloadsEqual(a: AccessibilityEvent, b: AccessibilityEvent): boolean {\n // Compare everything except timestamp\n // We compare: type, target, and payload\n if (a.type !== b.type) return false;\n if (!targetsEqual(a.target, b.target)) return false;\n return deepEqual(a.payload, b.payload);\n}\n\n/**\n * Compare two EventTarget objects for equality.\n */\nfunction targetsEqual(\n a: AccessibilityEvent['target'],\n b: AccessibilityEvent['target']\n): boolean {\n return (\n a.role === b.role &&\n a.accessibleName === b.accessibleName &&\n a.selector === b.selector\n );\n}\n\n/**\n * Deep equality check for payload objects.\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n if (typeof a !== 'object') return a === b;\n\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n\n const aKeys = Object.keys(aObj).sort();\n const bKeys = Object.keys(bObj).sort();\n\n if (aKeys.length !== bKeys.length) return false;\n\n for (let i = 0; i < aKeys.length; i++) {\n if (aKeys[i] !== bKeys[i]) return false;\n if (!deepEqual(aObj[aKeys[i]], bObj[bKeys[i]])) return false;\n }\n\n return true;\n}\n\n/**\n * Build a human-readable message describing a modification.\n */\nfunction buildModifiedMessage(\n baseline: AccessibilityEvent,\n current: AccessibilityEvent\n): string {\n const type = current.type;\n const selector = current.target.selector;\n\n // Check if target properties changed\n if (baseline.target.accessibleName !== current.target.accessibleName) {\n return (\n `${type} on \"${selector}\": accessible name changed from ` +\n `\"${baseline.target.accessibleName}\" to \"${current.target.accessibleName}\"`\n );\n }\n\n if (baseline.target.role !== current.target.role) {\n return (\n `${type} on \"${selector}\": role changed from ` +\n `\"${baseline.target.role}\" to \"${current.target.role}\"`\n );\n }\n\n // Generic payload difference message\n return `${type} on \"${selector}\": payload values differ`;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Compare two Accessibility Timelines and produce a structured diff report.\n *\n * Algorithm:\n * 1. Create matching keys for events: type + target selector\n * 2. Walk baseline events and find matching current events\n * 3. If matched: compare payloads (ignoring timestamp). Different = modified.\n * 4. If no match in current: classify as removed\n * 5. Unmatched current events: classify as added\n * 6. Timestamp-only differences do NOT count as modifications\n */\nexport function diffTimelines(\n baseline: AccessibilityTimeline,\n current: AccessibilityTimeline\n): BehaviorDiffReport {\n const added: DiffEntry[] = [];\n const removed: DiffEntry[] = [];\n const modified: DiffEntry[] = [];\n\n // Group current events by matching key, maintaining order within each key.\n // We use arrays to handle multiple events with the same key (e.g., multiple\n // focus changes on the same element).\n const currentByKey = new Map<string, AccessibilityEvent[]>();\n for (const event of current.events) {\n const key = matchingKey(event);\n const existing = currentByKey.get(key);\n if (existing) {\n existing.push(event);\n } else {\n currentByKey.set(key, [event]);\n }\n }\n\n // Track which current events have been matched to a baseline event\n const matchedCurrentIndices = new Set<string>();\n\n // Walk through baseline events\n for (const baselineEvent of baseline.events) {\n const key = matchingKey(baselineEvent);\n const candidates = currentByKey.get(key);\n\n if (!candidates || candidates.length === 0) {\n // No matching event in current timeline\n removed.push({\n event: baselineEvent,\n message: `${baselineEvent.type} on \"${baselineEvent.target.selector}\" was removed`,\n });\n continue;\n }\n\n // Find the first unmatched candidate with the same key\n let matched = false;\n for (let i = 0; i < candidates.length; i++) {\n const candidateId = `${key}::${i}`;\n if (matchedCurrentIndices.has(candidateId)) continue;\n\n const currentEvent = candidates[i];\n matchedCurrentIndices.add(candidateId);\n\n // Compare ignoring timestamp\n if (!payloadsEqual(baselineEvent, currentEvent)) {\n modified.push({\n event: currentEvent,\n previousEvent: baselineEvent,\n message: buildModifiedMessage(baselineEvent, currentEvent),\n });\n }\n // If payloads are equal (only timestamp differs), it is not a modification\n\n matched = true;\n break;\n }\n\n if (!matched) {\n // All candidates with this key were already consumed\n removed.push({\n event: baselineEvent,\n message: `${baselineEvent.type} on \"${baselineEvent.target.selector}\" was removed`,\n });\n }\n }\n\n // Any unmatched current events are additions\n for (const [key, candidates] of currentByKey.entries()) {\n for (let i = 0; i < candidates.length; i++) {\n const candidateId = `${key}::${i}`;\n if (!matchedCurrentIndices.has(candidateId)) {\n const event = candidates[i];\n added.push({\n event,\n message: `${event.type} on \"${event.target.selector}\" was added`,\n });\n }\n }\n }\n\n return {\n baseline: { totalEvents: baseline.events.length },\n current: { totalEvents: current.events.length },\n added,\n removed,\n modified,\n summary: {\n totalBaseline: baseline.events.length,\n totalCurrent: current.events.length,\n added: added.length,\n removed: removed.length,\n modified: modified.length,\n },\n };\n}\n","import type { AccessibilityEvent } from './types.js';\nimport type { BehaviorDiffReport, DiffEntry } from './diff-engine.js';\n\nexport type SeverityLevel = 'critical' | 'high' | 'medium' | 'low';\n\nexport interface ClassifiedDiffEntry {\n event: AccessibilityEvent;\n previousEvent?: AccessibilityEvent;\n message: string;\n severity: SeverityLevel;\n}\n\nexport interface ClassifiedDiffReport {\n entries: ClassifiedDiffEntry[];\n highestSeverity: SeverityLevel | null;\n criticalCount: number;\n highCount: number;\n mediumCount: number;\n lowCount: number;\n}\n\nexport function classifyDiff(report: BehaviorDiffReport): ClassifiedDiffReport {\n const entries: ClassifiedDiffEntry[] = [];\n\n // Removed events\n for (const entry of report.removed) {\n const severity = classifyRemoved(entry);\n entries.push({ ...entry, severity });\n }\n\n // Added events\n for (const entry of report.added) {\n const severity = classifyAdded(entry);\n entries.push({ ...entry, severity });\n }\n\n // Modified events\n for (const entry of report.modified) {\n const severity = classifyModified(entry);\n entries.push({ ...entry, severity });\n }\n\n const criticalCount = entries.filter(e => e.severity === 'critical').length;\n const highCount = entries.filter(e => e.severity === 'high').length;\n const mediumCount = entries.filter(e => e.severity === 'medium').length;\n const lowCount = entries.filter(e => e.severity === 'low').length;\n\n let highestSeverity: SeverityLevel | null = null;\n if (criticalCount > 0) highestSeverity = 'critical';\n else if (highCount > 0) highestSeverity = 'high';\n else if (mediumCount > 0) highestSeverity = 'medium';\n else if (lowCount > 0) highestSeverity = 'low';\n\n return { entries, highestSeverity, criticalCount, highCount, mediumCount, lowCount };\n}\n\nfunction classifyRemoved(entry: DiffEntry): SeverityLevel {\n switch (entry.event.type) {\n case 'FOCUS_CHANGED': return 'critical';\n case 'ANNOUNCEMENT': return 'critical';\n case 'DIALOG_OPENED': return 'high';\n case 'DIALOG_CLOSED': return 'high';\n case 'STATE_CHANGED': return 'high';\n case 'KEYBOARD_ACTION': return 'medium';\n default: return 'medium';\n }\n}\n\nfunction classifyAdded(entry: DiffEntry): SeverityLevel {\n switch (entry.event.type) {\n case 'WARNING': return 'high';\n case 'REGRESSION': return 'critical';\n case 'ANNOUNCEMENT': return 'medium';\n case 'FOCUS_CHANGED': return 'medium';\n default: return 'low';\n }\n}\n\nfunction classifyModified(entry: DiffEntry): SeverityLevel {\n switch (entry.event.type) {\n case 'FOCUS_CHANGED': return 'high';\n case 'STATE_CHANGED': return 'high';\n case 'ACCESSIBLE_NAME_CHANGED': return 'medium';\n case 'ANNOUNCEMENT': return 'medium';\n default: return 'medium';\n }\n}\n","import { readFile, writeFile, mkdir, access } from 'fs/promises';\nimport { join, dirname } from 'path';\nimport type { AccessibilityTimeline } from './types.js';\nimport { SPEAKABLE_VERSION } from '../version.js';\n\nexport interface BaselineFile {\n baseline: {\n createdAt: string;\n speakableVersion: string;\n storybookUrl?: string;\n interactionSequence: string;\n };\n timeline: AccessibilityTimeline;\n}\n\nexport interface BaselineStorage {\n save(componentName: string, storyName: string, timeline: AccessibilityTimeline, meta?: { storybookUrl?: string }): Promise<void>;\n load(componentName: string, storyName: string): Promise<BaselineFile | null>;\n exists(componentName: string, storyName: string): Promise<boolean>;\n getBaselinePath(componentName: string, storyName: string): string;\n}\n\nexport function createBaselineStorage(baseDir: string): BaselineStorage {\n function sanitize(name: string): string {\n return name.toLowerCase().replace(/[/\\\\]/g, '-').replace(/[^a-z0-9._-]/g, '-');\n }\n\n function getPath(componentName: string, storyName: string): string {\n return join(baseDir, sanitize(componentName), `${sanitize(storyName)}.timeline.json`);\n }\n\n return {\n async save(componentName, storyName, timeline, meta) {\n const filePath = getPath(componentName, storyName);\n const dir = dirname(filePath);\n\n try {\n await mkdir(dir, { recursive: true });\n } catch (err) {\n throw new Error(`Cannot create baseline directory \"${dir}\": ${(err as Error).message}`);\n }\n\n const baselineFile: BaselineFile = {\n baseline: {\n createdAt: new Date().toISOString(),\n speakableVersion: SPEAKABLE_VERSION,\n storybookUrl: meta?.storybookUrl,\n interactionSequence: timeline.interactionSequence,\n },\n timeline,\n };\n\n const json = JSON.stringify(baselineFile, null, 2);\n\n try {\n await writeFile(filePath, json, 'utf-8');\n } catch (err) {\n throw new Error(`Cannot write baseline file \"${filePath}\": ${(err as Error).message}`);\n }\n },\n\n async load(componentName, storyName) {\n const filePath = getPath(componentName, storyName);\n try {\n const content = await readFile(filePath, 'utf-8');\n const parsed = JSON.parse(content) as BaselineFile;\n return parsed;\n } catch {\n return null;\n }\n },\n\n async exists(componentName, storyName) {\n const filePath = getPath(componentName, storyName);\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n },\n\n getBaselinePath(componentName, storyName) {\n return getPath(componentName, storyName);\n },\n };\n}\n","/**\n * Verbosity Analyzer\n *\n * Detects redundant and duplicate announcement patterns in accessibility\n * event timelines. While the heuristic analyzer catches \"too many announcements\n * in a time window,\" this module performs deeper semantic analysis to identify\n * WHY announcements are being duplicated, and provides specific remediation\n * guidance.\n *\n * Detected patterns:\n *\n * 1. **Redundant state + live region** — When aria-selected/aria-checked changes\n * on an element AND a live region announces the same state change, screen\n * readers (especially VoiceOver) will read both.\n *\n * 2. **ActiveDescendant + state change on same element** — When\n * aria-activedescendant moves to an element AND that element's state changes\n * in the same interaction frame, VoiceOver reads the element twice.\n *\n * 3. **Name change + live region echo** — When an element's accessible name\n * changes and a live region repeats that same content.\n *\n * 4. **Focus + activedescendant conflict** — When real DOM focus moves AND\n * aria-activedescendant changes in the same frame, causing double-read.\n *\n * 5. **Multiple state changes on one element** — When several ARIA attributes\n * change simultaneously on a single element, each triggering a separate read.\n *\n * @module runtime/verbosity-analyzer\n */\n\nimport type { AccessibilityEvent, StateChangedPayload, AnnouncementPayload } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Severity of a verbosity issue.\n * - \"high\": Users will definitely hear duplicate content (e.g., VoiceOver triple-read)\n * - \"medium\": Users will likely hear repeated info depending on screen reader settings\n * - \"low\": Potential redundancy that may only affect certain screen readers\n */\nexport type VerbositySeverity = 'high' | 'medium' | 'low';\n\n/**\n * Category of the verbosity pattern detected.\n */\nexport type VerbosityPattern =\n | 'redundant-state-and-live-region'\n | 'activedescendant-plus-state-change'\n | 'name-change-plus-live-region'\n | 'focus-plus-activedescendant'\n | 'multiple-state-changes-same-element'\n | 'rapid-identical-announcements';\n\n/**\n * A single verbosity finding with context and remediation guidance.\n */\nexport interface VerbosityFinding {\n /** Pattern category */\n pattern: VerbosityPattern;\n /** Severity level */\n severity: VerbositySeverity;\n /** Human-readable description of the problem */\n description: string;\n /** Specific remediation steps */\n remediation: string[];\n /** Which screen readers are most affected */\n affectedReaders: string[];\n /** The events that triggered this finding */\n relatedEvents: AccessibilityEvent[];\n /** Timestamp window where the duplicate occurred */\n timeWindow: { start: number; end: number };\n /** CSS selector of the element involved */\n elementSelector: string;\n}\n\n/**\n * Complete verbosity analysis report for a timeline.\n */\nexport interface VerbosityReport {\n /** All findings sorted by severity (high first) */\n findings: VerbosityFinding[];\n /** Summary counts by severity */\n summary: {\n high: number;\n medium: number;\n low: number;\n total: number;\n };\n /** Overall verbosity score (0-100, lower is better) */\n score: number;\n}\n\n/**\n * Configuration for the verbosity analyzer.\n */\nexport interface VerbosityConfig {\n /** Time window (ms) to group related events into a single interaction frame (default: 150) */\n interactionFrameWindow: number;\n /** Minimum text similarity ratio to consider live region content redundant (default: 0.6) */\n textSimilarityThreshold: number;\n}\n\nconst DEFAULT_CONFIG: VerbosityConfig = {\n interactionFrameWindow: 150,\n textSimilarityThreshold: 0.6,\n};\n\n// ---------------------------------------------------------------------------\n// Text Similarity\n// ---------------------------------------------------------------------------\n\n/**\n * Computes a simple word-overlap similarity ratio between two strings.\n * Returns a value between 0 and 1.\n */\nfunction textSimilarity(a: string, b: string): number {\n if (!a || !b) return 0;\n const wordsA = new Set(a.toLowerCase().split(/\\s+/).filter(Boolean));\n const wordsB = new Set(b.toLowerCase().split(/\\s+/).filter(Boolean));\n if (wordsA.size === 0 || wordsB.size === 0) return 0;\n\n let overlap = 0;\n for (const word of wordsA) {\n if (wordsB.has(word)) overlap++;\n }\n\n const maxSize = Math.max(wordsA.size, wordsB.size);\n return overlap / maxSize;\n}\n\n// ---------------------------------------------------------------------------\n// Interaction Frame Grouping\n// ---------------------------------------------------------------------------\n\ninterface InteractionFrame {\n start: number;\n end: number;\n events: AccessibilityEvent[];\n}\n\n/**\n * Groups events into interaction frames based on temporal proximity.\n * Events within `windowMs` of each other are considered part of the\n * same user interaction.\n */\nfunction groupIntoFrames(events: AccessibilityEvent[], windowMs: number): InteractionFrame[] {\n if (events.length === 0) return [];\n\n const frames: InteractionFrame[] = [];\n let currentFrame: InteractionFrame = {\n start: events[0].timestamp,\n end: events[0].timestamp,\n events: [events[0]],\n };\n\n for (let i = 1; i < events.length; i++) {\n const event = events[i];\n if (event.timestamp - currentFrame.end <= windowMs) {\n currentFrame.events.push(event);\n currentFrame.end = event.timestamp;\n } else {\n frames.push(currentFrame);\n currentFrame = {\n start: event.timestamp,\n end: event.timestamp,\n events: [event],\n };\n }\n }\n\n frames.push(currentFrame);\n return frames;\n}\n\n// ---------------------------------------------------------------------------\n// Pattern Detection\n// ---------------------------------------------------------------------------\n\nfunction detectRedundantStateAndLiveRegion(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const stateChanges = frame.events.filter((e) => e.type === 'STATE_CHANGED');\n const announcements = frame.events.filter((e) => e.type === 'ANNOUNCEMENT');\n\n for (const stateEvent of stateChanges) {\n const payload = stateEvent.payload as StateChangedPayload;\n\n // Only relevant for state attributes that screen readers announce\n const announcedAttributes = [\n 'aria-selected', 'aria-checked', 'aria-pressed', 'aria-expanded',\n 'aria-disabled', 'aria-invalid', 'aria-current',\n ];\n if (!announcedAttributes.includes(payload.attribute)) continue;\n\n for (const announcement of announcements) {\n const annoPayload = announcement.payload as AnnouncementPayload;\n const annoText = annoPayload.text.toLowerCase();\n const elementName = stateEvent.target.accessibleName.toLowerCase();\n\n // Check if the live region text contains the element's name\n // (which indicates it's providing feedback about the same element\n // whose state just changed, meaning the SR will announce both)\n const nameInAnnouncement = elementName.length > 0 && annoText.includes(elementName);\n\n // Also check for state-related words that echo what the SR already announces\n const stateEchoWords = ['selected', 'deselected', 'checked', 'unchecked', 'expanded', 'collapsed', 'pressed'];\n const hasStateEcho = stateEchoWords.some((word) => annoText.includes(word));\n\n if (nameInAnnouncement && hasStateEcho) {\n findings.push({\n pattern: 'redundant-state-and-live-region',\n severity: 'high',\n description:\n `The ${payload.attribute} state change on \"${stateEvent.target.accessibleName}\" ` +\n `(${stateEvent.target.role}) is already announced by the screen reader, but a live ` +\n `region also announces similar content (\"${annoPayload.text}\"). ` +\n `This causes VoiceOver to read the information 2-3 times.`,\n remediation: [\n `Remove the live region announcement when ${payload.attribute} changes on the active element, ` +\n `since the screen reader already announces state transitions on the focused/active item.`,\n `If you need the live region for summary info (e.g., \"3 of 5 selected\"), ` +\n `debounce it with a 150ms+ delay and ensure the text does NOT repeat the option name.`,\n `Use a summary-only pattern in the live region: \"3 of 5 selected\" instead of ` +\n `\"JavaScript selected. 3 of 5 selected.\" The element name is already announced ` +\n `via the state change.`,\n `Consider removing the live region entirely and relying on aria-selected/aria-checked ` +\n `state changes for per-item feedback.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'VoiceOver (iOS)'],\n relatedEvents: [stateEvent, announcement],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: stateEvent.target.selector,\n });\n }\n }\n }\n\n return findings;\n}\n\nfunction detectActiveDescendantPlusStateChange(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n // Look for STATE_CHANGED events where attribute is aria-activedescendant\n const activedescendantChanges = frame.events.filter(\n (e) => e.type === 'STATE_CHANGED' &&\n (e.payload as StateChangedPayload).attribute === 'aria-activedescendant'\n );\n\n const otherStateChanges = frame.events.filter(\n (e) => e.type === 'STATE_CHANGED' &&\n (e.payload as StateChangedPayload).attribute !== 'aria-activedescendant'\n );\n\n for (const adChange of activedescendantChanges) {\n const adPayload = adChange.payload as StateChangedPayload;\n const newValue = String(adPayload.newValue);\n const previousValue = String(adPayload.previousValue ?? '');\n\n // If activedescendant is being re-set to the SAME value, that's always a bug.\n // If it's moving to a DIFFERENT element, we only flag it if a state change\n // occurs on that same target within the frame (which causes double-read on VoiceOver).\n const isSameElement = newValue === previousValue;\n\n for (const stateChange of otherStateChanges) {\n const statePayload = stateChange.payload as StateChangedPayload;\n\n // Check if the state change is on the element that activedescendant points to\n const targetMatchesAD = stateChange.target.selector.includes(newValue) ||\n stateChange.target.selector === adChange.target.selector;\n\n if (!targetMatchesAD) continue;\n\n if (isSameElement) {\n // Definite bug: re-setting activedescendant to same element AND changing its state\n findings.push({\n pattern: 'activedescendant-plus-state-change',\n severity: 'high',\n description:\n `aria-activedescendant was re-set to the same value (\"${newValue}\") ` +\n `AND ${statePayload.attribute} changed on that element within ${frame.end - frame.start}ms. ` +\n `VoiceOver reads the element once for the activedescendant update, then again for the state change.`,\n remediation: [\n `When toggling selection on the already-active option, do NOT re-set aria-activedescendant ` +\n `to the same value. Only update it when the user navigates to a different option.`,\n `Batch DOM attribute changes: set aria-selected BEFORE updating aria-activedescendant, ` +\n `or skip the activedescendant update entirely when the active item hasn't changed.`,\n `For click interactions on options, avoid calling both setActiveDescendant() and ` +\n `toggleSelection() if the clicked item is already the active descendant.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'VoiceOver (iOS)', 'Narrator'],\n relatedEvents: [adChange, stateChange],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: stateChange.target.selector,\n });\n } else {\n // Moving to a different element + changing state is borderline.\n // Only flag as low severity since VoiceOver announcing the navigation\n // AND the state is sometimes the desired UX (click = navigate + select).\n findings.push({\n pattern: 'activedescendant-plus-state-change',\n severity: 'low',\n description:\n `aria-activedescendant moved to \"${stateChange.target.accessibleName}\" ` +\n `AND ${statePayload.attribute} changed on that element within ${frame.end - frame.start}ms. ` +\n `VoiceOver may announce the option name twice (once for navigation, once for state).`,\n remediation: [\n `If this is a click-to-select interaction, consider separating the activedescendant ` +\n `update and the state change by a microtask (Promise.resolve()) so VoiceOver ` +\n `processes them as separate assertions.`,\n `Alternatively, accept this as expected behavior for click interactions where ` +\n `navigation and selection happen simultaneously.`,\n ],\n affectedReaders: ['VoiceOver (macOS)'],\n relatedEvents: [adChange, stateChange],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: stateChange.target.selector,\n });\n }\n }\n }\n\n return findings;\n}\n\nfunction detectNameChangePlusLiveRegion(\n frame: InteractionFrame,\n config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const nameChanges = frame.events.filter((e) => e.type === 'ACCESSIBLE_NAME_CHANGED');\n const announcements = frame.events.filter((e) => e.type === 'ANNOUNCEMENT');\n\n for (const nameEvent of nameChanges) {\n for (const announcement of announcements) {\n const annoPayload = announcement.payload as AnnouncementPayload;\n const similarity = textSimilarity(nameEvent.target.accessibleName, annoPayload.text);\n\n if (similarity >= config.textSimilarityThreshold) {\n findings.push({\n pattern: 'name-change-plus-live-region',\n severity: 'medium',\n description:\n `The accessible name of \"${nameEvent.target.accessibleName}\" (${nameEvent.target.role}) ` +\n `changed AND a live region announced similar content (\"${annoPayload.text}\"). ` +\n `Screen readers may announce both the name change and the live region.`,\n remediation: [\n `Choose one announcement channel: either update the element's accessible name ` +\n `(which the screen reader reads if the element is focused) OR use a live region, not both.`,\n `If the element is focused, prefer the name change. If it's not focused, prefer the live region.`,\n `Add a 200ms+ debounce to the live region update to let the name change announce first.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'NVDA', 'JAWS'],\n relatedEvents: [nameEvent, announcement],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: nameEvent.target.selector,\n });\n }\n }\n }\n\n return findings;\n}\n\nfunction detectFocusPlusActiveDescendant(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const focusEvents = frame.events.filter((e) => e.type === 'FOCUS_CHANGED');\n const adChanges = frame.events.filter(\n (e) => e.type === 'STATE_CHANGED' &&\n (e.payload as StateChangedPayload).attribute === 'aria-activedescendant'\n );\n\n if (focusEvents.length > 0 && adChanges.length > 0) {\n findings.push({\n pattern: 'focus-plus-activedescendant',\n severity: 'medium',\n description:\n `Both real DOM focus moved AND aria-activedescendant changed within ${frame.end - frame.start}ms. ` +\n `Screen readers may announce the focused element AND then re-announce via activedescendant, ` +\n `causing a double-read.`,\n remediation: [\n `Choose one focus management strategy: either move real DOM focus to options (roving tabindex) ` +\n `OR use aria-activedescendant on the container. Do not mix both.`,\n `If using aria-activedescendant, keep DOM focus on the container (listbox/combobox) ` +\n `and only change the activedescendant attribute.`,\n `If using roving tabindex, set tabindex=\"0\" on the active item and tabindex=\"-1\" on others, ` +\n `and move focus directly via element.focus().`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'NVDA', 'JAWS', 'Narrator'],\n relatedEvents: [...focusEvents, ...adChanges],\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: focusEvents[0].target.selector,\n });\n }\n\n return findings;\n}\n\nfunction detectMultipleStateChangesSameElement(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const stateChanges = frame.events.filter((e) => e.type === 'STATE_CHANGED');\n\n // Group by target selector\n const bySelector = new Map<string, AccessibilityEvent[]>();\n for (const event of stateChanges) {\n const existing = bySelector.get(event.target.selector) || [];\n existing.push(event);\n bySelector.set(event.target.selector, existing);\n }\n\n for (const [selector, events] of bySelector) {\n if (events.length >= 3) {\n const attributes = events.map((e) => (e.payload as StateChangedPayload).attribute);\n findings.push({\n pattern: 'multiple-state-changes-same-element',\n severity: 'medium',\n description:\n `${events.length} ARIA attributes changed simultaneously on \"${events[0].target.accessibleName}\" ` +\n `(${events[0].target.role}): ${attributes.join(', ')}. ` +\n `Some screen readers announce each attribute change individually, ` +\n `causing a verbose multi-part announcement.`,\n remediation: [\n `Batch attribute changes into a single DOM mutation frame by setting all attributes ` +\n `before the next microtask. Use requestAnimationFrame() or Promise.resolve() to group them.`,\n `Evaluate which attributes actually need to be communicated. For example, ` +\n `if aria-selected changes, the screen reader already announces it; additional ` +\n `aria-checked or aria-pressed changes may be redundant.`,\n `Consider using a single composite state (e.g., just aria-selected for listbox options) ` +\n `rather than multiple state attributes.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'Narrator'],\n relatedEvents: events,\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: selector,\n });\n }\n }\n\n return findings;\n}\n\nfunction detectRapidIdenticalAnnouncements(\n frame: InteractionFrame,\n _config: VerbosityConfig\n): VerbosityFinding[] {\n const findings: VerbosityFinding[] = [];\n\n const announcements = frame.events.filter((e) => e.type === 'ANNOUNCEMENT');\n\n // Check for identical or near-identical announcement text\n const seen = new Map<string, AccessibilityEvent[]>();\n for (const event of announcements) {\n const text = (event.payload as AnnouncementPayload).text.toLowerCase().trim();\n const existing = seen.get(text) || [];\n existing.push(event);\n seen.set(text, existing);\n }\n\n for (const [text, events] of seen) {\n if (events.length >= 2) {\n findings.push({\n pattern: 'rapid-identical-announcements',\n severity: 'high',\n description:\n `The same live region content (\"${text}\") was announced ${events.length} times ` +\n `within ${frame.end - frame.start}ms. Users will hear the same information repeated.`,\n remediation: [\n `Debounce live region updates. Clear the live region text content first, ` +\n `then set the new value after a 100-200ms delay.`,\n `If updating a live region's textContent to the same value, the screen reader ` +\n `may ignore it OR re-read it depending on implementation. Clear to empty string first.`,\n `Avoid updating the live region inside a loop or rapid event handler. ` +\n `Compute the final state and announce once.`,\n ],\n affectedReaders: ['VoiceOver (macOS)', 'VoiceOver (iOS)', 'NVDA', 'Narrator'],\n relatedEvents: events,\n timeWindow: { start: frame.start, end: frame.end },\n elementSelector: events[0].target.selector,\n });\n }\n }\n\n return findings;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Analyzes a timeline of accessibility events for verbosity issues.\n *\n * Groups events into interaction frames (events within a short time window\n * of each other), then checks each frame for patterns that cause screen\n * readers to announce redundant or duplicate content.\n *\n * @param events - Chronologically ordered accessibility events\n * @param config - Optional configuration overrides\n * @returns A VerbosityReport with all findings and a score\n */\nexport function analyzeVerbosity(\n events: AccessibilityEvent[],\n config?: Partial<VerbosityConfig>\n): VerbosityReport {\n const cfg: VerbosityConfig = { ...DEFAULT_CONFIG, ...config };\n\n // Group events into interaction frames\n const frames = groupIntoFrames(events, cfg.interactionFrameWindow);\n\n // Run all detectors on each frame\n const findings: VerbosityFinding[] = [];\n\n for (const frame of frames) {\n findings.push(...detectRedundantStateAndLiveRegion(frame, cfg));\n findings.push(...detectActiveDescendantPlusStateChange(frame, cfg));\n findings.push(...detectNameChangePlusLiveRegion(frame, cfg));\n findings.push(...detectFocusPlusActiveDescendant(frame, cfg));\n findings.push(...detectMultipleStateChangesSameElement(frame, cfg));\n findings.push(...detectRapidIdenticalAnnouncements(frame, cfg));\n }\n\n // Sort by severity (high first)\n const severityOrder: Record<VerbositySeverity, number> = { high: 0, medium: 1, low: 2 };\n findings.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);\n\n // Compute summary\n const summary = {\n high: findings.filter((f) => f.severity === 'high').length,\n medium: findings.filter((f) => f.severity === 'medium').length,\n low: findings.filter((f) => f.severity === 'low').length,\n total: findings.length,\n };\n\n // Score: 100 (perfect) minus weighted deductions\n const deductions = summary.high * 25 + summary.medium * 10 + summary.low * 3;\n const score = Math.max(0, 100 - deductions);\n\n return { findings, summary, score };\n}\n\n/**\n * Formats a verbosity report as human-readable text output.\n */\nexport function formatVerbosityReport(report: VerbosityReport): string {\n const lines: string[] = [];\n\n lines.push('');\n lines.push('=== VERBOSITY ANALYSIS REPORT ===');\n lines.push('');\n lines.push(`Score: ${report.score}/100 ${report.score >= 80 ? '(Good)' : report.score >= 50 ? '(Needs attention)' : '(Critical verbosity issues)'}`);\n lines.push(`Findings: ${report.summary.total} (${report.summary.high} high, ${report.summary.medium} medium, ${report.summary.low} low)`);\n lines.push('');\n\n if (report.findings.length === 0) {\n lines.push('No verbosity issues detected. Announcements appear clean.');\n return lines.join('\\n');\n }\n\n for (let i = 0; i < report.findings.length; i++) {\n const finding = report.findings[i];\n const severityIcon = finding.severity === 'high' ? '\\u2718' : finding.severity === 'medium' ? '\\u26A0' : '\\u2139';\n\n lines.push(`${severityIcon} [${finding.severity.toUpperCase()}] ${finding.pattern}`);\n lines.push(` Element: ${finding.elementSelector}`);\n lines.push(` Window: ${finding.timeWindow.start}ms - ${finding.timeWindow.end}ms`);\n lines.push(` ${finding.description}`);\n lines.push('');\n lines.push(' Affected: ' + finding.affectedReaders.join(', '));\n lines.push('');\n lines.push(' Remediation:');\n for (const step of finding.remediation) {\n lines.push(` - ${step}`);\n }\n lines.push('');\n\n if (i < report.findings.length - 1) {\n lines.push(' ' + '\\u2500'.repeat(60));\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":["childPath","pc","formatValue","pc","shouldAnnounceRoleFirst","model","computeAccessibleName","buildEventTarget","computeAccessibleName","getElementRole","buildEventTarget","buildEventTarget","buildEventTarget","computeAccessibleName","getElementRole","DEFAULT_CONFIG"]}
|