/** * Core Metrics Analysis Engine * * Implements the main BFS traversal algorithm from the Ruby aac-metrics tool. * Calculates effort scores for all buttons in an AAC board set. * * Based on: aac-metrics/lib/aac-metrics/metrics.rb */ import { AACTree } from '../../../core/treeStructure'; import { MetricsOptions, MetricsResult } from './types'; export declare class MetricsCalculator { private locale; /** * Main analysis function - calculates metrics for an AAC tree * * @param tree - The AAC tree to analyze * @param options - Optional configuration for metrics calculation * @returns Complete metrics result */ analyze(tree: AACTree, options?: MetricsOptions): MetricsResult; /** * Identify keyboard/spelling page and calculate base/avg effort */ private identifySpellingMetrics; /** * Build reference maps for semantic_id and clone_id frequencies */ private buildReferenceMaps; /** * Count scan items for visual scanning effort * When block scanning is enabled, count unique scan blocks instead of individual buttons */ private countScanBlocks; /** * Analyze starting from a specific board */ private analyzeFrom; /** * Calculate what percentage of links to this board match semantic_id/clone_id */ private calculateBoardLinkPercentages; /** * Quick check whether any button in the tree has a POS tag. * Used to auto-enable smart grammar without requiring explicit opt-in. * * IMPORTANT: Only counts POS from non-Inflector and non-Suffix buttons. * TDSnap Inflector buttons and Grid3 Suffix buttons are grammar controls, * not content words — they should NOT auto-enable morphology. */ private treeHasPosTags; /** * Expand morphological predictions from POS tags on buttons * * For each button that has a POS tag (e.g., 'Verb', 'Noun'), use the * MorphologyEngine to generate inflected word forms and populate the * button's predictions array. This is done as a pre-processing step * before calculateWordFormMetrics assigns effort to each form. */ private expandMorphologicalPredictions; /** * Expand morphological predictions for Grid3 pagesets. * * Grid3 uses suffix buttons (pos='Suffix') on the same page as content words. * Different pages have different suffix buttons — e.g., topic pages may only * have -s (plural), while the Magic Wand page has -s, -er, -est, -ly, -y, -'s. * * Rules: * 1. Build a suffix→formSlot map (-s → plural, -er → comparative, etc.) * 2. For each page, collect available suffix buttons * 3. Only generate forms for slots that have matching suffix buttons on that page * 4. POS inference is used for untagged content words (Grid3 grids often lack POS) */ private expandGrid3Predictions; /** * Expand morphological predictions for TDSnap pagesets. * * TDSnap uses Inflector buttons (ContentType=3) on "Word Forms" pages to * provide morphology. These pages are loaded dynamically by the runtime, * NOT via navigation buttons, so they are unreachable in our tree model. * * Rules: * 1. If the pageset has NO Inflector buttons → no morphology at all * 2. Only generate forms whose grammar tag matches an available Inflector * (e.g., if there's no -ly Inflector, don't generate "happily") * 3. No POS inference — only the lexicon determines which words get forms */ private expandTDSnapPredictions; private filterFormsByAvailableTags; /** * Calculate metrics for word forms (smart grammar predictions) * * Word forms are dynamically generated and not part of the tree structure. * Their effort is calculated as: * - Parent button's cumulative effort (to reach the button) * - + Effort to select the word form from its position in predictions grid * * If a word exists as both a regular button and a word form, the version * with lower effort is kept. * * @param tree - The AAC tree * @param buttons - Already calculated button metrics * @param options - Metrics options * @returns Object containing word form metrics and labels that were replaced */ private calculateWordFormMetrics; /** * Calculate grid dimensions from the tree */ private calculateGridDimensions; /** * Calculate scanning steps and selections for a button based on access method */ private calculateScanSteps; }