@willwade/aac-processors 0.0.10 → 0.0.12

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.
Files changed (57) hide show
  1. package/dist/cli/index.js +7 -0
  2. package/dist/core/analyze.js +1 -0
  3. package/dist/core/baseProcessor.d.ts +3 -0
  4. package/dist/core/treeStructure.d.ts +14 -2
  5. package/dist/core/treeStructure.js +8 -2
  6. package/dist/index.d.ts +2 -1
  7. package/dist/index.js +20 -3
  8. package/dist/{analytics → optional/analytics}/history.d.ts +3 -3
  9. package/dist/{analytics → optional/analytics}/history.js +3 -3
  10. package/dist/optional/analytics/index.d.ts +28 -0
  11. package/dist/optional/analytics/index.js +73 -0
  12. package/dist/optional/analytics/metrics/comparison.d.ts +36 -0
  13. package/dist/optional/analytics/metrics/comparison.js +330 -0
  14. package/dist/optional/analytics/metrics/core.d.ts +36 -0
  15. package/dist/optional/analytics/metrics/core.js +422 -0
  16. package/dist/optional/analytics/metrics/effort.d.ts +137 -0
  17. package/dist/optional/analytics/metrics/effort.js +198 -0
  18. package/dist/optional/analytics/metrics/index.d.ts +15 -0
  19. package/dist/optional/analytics/metrics/index.js +36 -0
  20. package/dist/optional/analytics/metrics/sentence.d.ts +49 -0
  21. package/dist/optional/analytics/metrics/sentence.js +112 -0
  22. package/dist/optional/analytics/metrics/types.d.ts +157 -0
  23. package/dist/optional/analytics/metrics/types.js +7 -0
  24. package/dist/optional/analytics/metrics/vocabulary.d.ts +65 -0
  25. package/dist/optional/analytics/metrics/vocabulary.js +140 -0
  26. package/dist/optional/analytics/reference/index.d.ts +51 -0
  27. package/dist/optional/analytics/reference/index.js +102 -0
  28. package/dist/optional/analytics/utils/idGenerator.d.ts +59 -0
  29. package/dist/optional/analytics/utils/idGenerator.js +96 -0
  30. package/dist/processors/gridset/colorUtils.d.ts +18 -0
  31. package/dist/processors/gridset/colorUtils.js +36 -0
  32. package/dist/processors/gridset/commands.d.ts +103 -0
  33. package/dist/processors/gridset/commands.js +958 -0
  34. package/dist/processors/gridset/index.d.ts +45 -0
  35. package/dist/processors/gridset/index.js +153 -0
  36. package/dist/processors/gridset/pluginTypes.d.ts +109 -0
  37. package/dist/processors/gridset/pluginTypes.js +285 -0
  38. package/dist/processors/gridset/resolver.d.ts +13 -0
  39. package/dist/processors/gridset/resolver.js +39 -1
  40. package/dist/processors/gridset/styleHelpers.d.ts +22 -0
  41. package/dist/processors/gridset/styleHelpers.js +35 -1
  42. package/dist/processors/gridset/symbolExtractor.d.ts +121 -0
  43. package/dist/processors/gridset/symbolExtractor.js +362 -0
  44. package/dist/processors/gridset/symbolSearch.d.ts +117 -0
  45. package/dist/processors/gridset/symbolSearch.js +280 -0
  46. package/dist/processors/gridset/symbols.d.ts +199 -0
  47. package/dist/processors/gridset/symbols.js +468 -0
  48. package/dist/processors/gridsetProcessor.js +59 -0
  49. package/dist/processors/index.d.ts +10 -1
  50. package/dist/processors/index.js +93 -2
  51. package/dist/processors/obfProcessor.js +25 -2
  52. package/dist/processors/obfsetProcessor.d.ts +26 -0
  53. package/dist/processors/obfsetProcessor.js +179 -0
  54. package/dist/processors/snapProcessor.js +29 -1
  55. package/dist/processors/touchchatProcessor.js +27 -0
  56. package/dist/types/aac.d.ts +21 -0
  57. package/package.json +1 -1
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /**
3
+ * Effort Score Calculation Algorithms
4
+ *
5
+ * Implements the core effort calculation algorithms from the Ruby aac-metrics tool.
6
+ * These algorithms calculate how difficult it is to access each button based on
7
+ * distance, visual scanning, grid complexity, and motor planning support.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.EFFORT_CONSTANTS = void 0;
11
+ exports.buttonSizeEffort = buttonSizeEffort;
12
+ exports.fieldSizeEffort = fieldSizeEffort;
13
+ exports.visualScanEffort = visualScanEffort;
14
+ exports.distanceEffort = distanceEffort;
15
+ exports.spellingEffort = spellingEffort;
16
+ exports.baseBoardEffort = baseBoardEffort;
17
+ exports.applyReuseDiscount = applyReuseDiscount;
18
+ exports.calculateButtonEffort = calculateButtonEffort;
19
+ exports.calculateDistanceWithDiscounts = calculateDistanceWithDiscounts;
20
+ exports.shouldSkipVisualScan = shouldSkipVisualScan;
21
+ exports.localScanEffort = localScanEffort;
22
+ /**
23
+ * Constants for effort score calculation
24
+ * Values match the Ruby implementation exactly
25
+ */
26
+ exports.EFFORT_CONSTANTS = {
27
+ SQRT2: Math.sqrt(2),
28
+ BUTTON_SIZE_MULTIPLIER: 0.09,
29
+ FIELD_SIZE_MULTIPLIER: 0.005,
30
+ VISUAL_SCAN_MULTIPLIER: 0.015,
31
+ BOARD_CHANGE_PROCESSING_EFFORT: 1.0,
32
+ BOARD_HOME_EFFORT: 1.0,
33
+ COMBINED_WORDS_REMEMBERING_EFFORT: 1.0,
34
+ DISTANCE_MULTIPLIER: 0.4,
35
+ DISTANCE_THRESHOLD_TO_SKIP_VISUAL_SCAN: 0.1,
36
+ SKIPPED_VISUAL_SCAN_DISTANCE_MULTIPLIER: 0.5,
37
+ SAME_LOCATION_AS_PRIOR_DISCOUNT: 0.1,
38
+ RECOGNIZABLE_SEMANTIC_FROM_PRIOR_DISCOUNT: 0.5,
39
+ RECOGNIZABLE_SEMANTIC_FROM_OTHER_DISCOUNT: 0.5,
40
+ REUSED_SEMANTIC_FROM_OTHER_BONUS: 0.0025,
41
+ RECOGNIZABLE_CLONE_FROM_PRIOR_DISCOUNT: 0.33,
42
+ RECOGNIZABLE_CLONE_FROM_OTHER_DISCOUNT: 0.33,
43
+ REUSED_CLONE_FROM_OTHER_BONUS: 0.005,
44
+ };
45
+ /**
46
+ * Calculate button size effort based on grid dimensions
47
+ * Larger grids require more visual scanning and discrimination
48
+ *
49
+ * @param rows - Number of rows in the grid
50
+ * @param cols - Number of columns in the grid
51
+ * @returns Button size effort score
52
+ */
53
+ function buttonSizeEffort(rows, cols) {
54
+ return exports.EFFORT_CONSTANTS.BUTTON_SIZE_MULTIPLIER * ((rows + cols) / 2);
55
+ }
56
+ /**
57
+ * Calculate field size effort based on number of visible buttons
58
+ * More buttons = more visual clutter = higher effort
59
+ *
60
+ * @param buttonCount - Number of visible buttons on the board
61
+ * @returns Field size effort score
62
+ */
63
+ function fieldSizeEffort(buttonCount) {
64
+ return exports.EFFORT_CONSTANTS.FIELD_SIZE_MULTIPLIER * buttonCount;
65
+ }
66
+ /**
67
+ * Calculate visual scanning effort
68
+ * Effort increases with each button that must be scanned before reaching target
69
+ *
70
+ * @param priorButtons - Number of buttons visually scanned before target
71
+ * @returns Visual scan effort score
72
+ */
73
+ function visualScanEffort(priorButtons) {
74
+ return priorButtons * exports.EFFORT_CONSTANTS.VISUAL_SCAN_MULTIPLIER;
75
+ }
76
+ /**
77
+ * Calculate distance effort from entry point to button center
78
+ * Uses Euclidean distance normalized by sqrt(2)
79
+ *
80
+ * @param x - Button center X coordinate (0-1 normalized)
81
+ * @param y - Button center Y coordinate (0-1 normalized)
82
+ * @param entryX - Entry point X coordinate (0-1 normalized, default 1.0 = bottom-right)
83
+ * @param entryY - Entry point Y coordinate (0-1 normalized, default 1.0 = bottom-right)
84
+ * @returns Distance effort score
85
+ */
86
+ function distanceEffort(x, y, entryX = 1.0, entryY = 1.0) {
87
+ const distance = Math.sqrt(Math.pow(x - entryX, 2) + Math.pow(y - entryY, 2));
88
+ return (distance / exports.EFFORT_CONSTANTS.SQRT2) * exports.EFFORT_CONSTANTS.DISTANCE_MULTIPLIER;
89
+ }
90
+ /**
91
+ * Calculate spelling effort for words not available in the board set
92
+ * Base cost + per-letter cost
93
+ *
94
+ * @param word - The word to spell
95
+ * @returns Spelling effort score
96
+ */
97
+ function spellingEffort(word) {
98
+ return 10 + word.length * 2.5;
99
+ }
100
+ /**
101
+ * Calculate base board effort
102
+ * Combines button size and field size efforts
103
+ *
104
+ * @param rows - Number of rows in the grid
105
+ * @param cols - Number of columns in the grid
106
+ * @param buttonCount - Number of visible buttons
107
+ * @returns Base board effort score
108
+ */
109
+ function baseBoardEffort(rows, cols, buttonCount) {
110
+ const sizeEffort = buttonSizeEffort(rows, cols);
111
+ const fieldEffort = fieldSizeEffort(buttonCount);
112
+ return sizeEffort + fieldEffort;
113
+ }
114
+ /**
115
+ * Apply reuse discount based on semantic_id/clone_id frequency
116
+ *
117
+ * @param boardEffort - Current board effort
118
+ * @param reuseDiscount - Calculated reuse discount
119
+ * @returns Adjusted board effort
120
+ */
121
+ function applyReuseDiscount(boardEffort, reuseDiscount) {
122
+ return Math.max(0, boardEffort - reuseDiscount);
123
+ }
124
+ /**
125
+ * Calculate button-level effort with motor planning discounts
126
+ *
127
+ * @param baseEffort - Base board effort
128
+ * @param boardPcts - Percentage of links matching semantic_id/clone_id
129
+ * @param button - Button data
130
+ * @returns Adjusted button effort
131
+ */
132
+ function calculateButtonEffort(baseEffort, boardPcts, button) {
133
+ let buttonEffort = baseEffort;
134
+ // Apply discounts for semantic_id
135
+ if (button.semantic_id && boardPcts[button.semantic_id]) {
136
+ const discount = exports.EFFORT_CONSTANTS.SAME_LOCATION_AS_PRIOR_DISCOUNT / boardPcts[button.semantic_id];
137
+ buttonEffort = Math.min(buttonEffort, buttonEffort * discount);
138
+ }
139
+ // Apply discounts for clone_id
140
+ if (button.clone_id && boardPcts[button.clone_id]) {
141
+ const discount = exports.EFFORT_CONSTANTS.SAME_LOCATION_AS_PRIOR_DISCOUNT / boardPcts[button.clone_id];
142
+ buttonEffort = Math.min(buttonEffort, buttonEffort * discount);
143
+ }
144
+ return buttonEffort;
145
+ }
146
+ /**
147
+ * Calculate distance with motor planning discounts
148
+ *
149
+ * @param distance - Raw distance effort
150
+ * @param boardPcts - Percentage of links matching semantic_id/clone_id
151
+ * @param button - Button data
152
+ * @param setPcts - Percentage of boards containing semantic_id/clone_id
153
+ * @returns Adjusted distance effort
154
+ */
155
+ function calculateDistanceWithDiscounts(distance, boardPcts, button, setPcts) {
156
+ let adjustedDistance = distance;
157
+ // Apply semantic_id discounts
158
+ if (button.semantic_id) {
159
+ if (boardPcts[button.semantic_id]) {
160
+ const discount = exports.EFFORT_CONSTANTS.SAME_LOCATION_AS_PRIOR_DISCOUNT / boardPcts[button.semantic_id];
161
+ adjustedDistance = Math.min(adjustedDistance, adjustedDistance * discount);
162
+ }
163
+ else if (setPcts[button.semantic_id]) {
164
+ const discount = exports.EFFORT_CONSTANTS.RECOGNIZABLE_SEMANTIC_FROM_OTHER_DISCOUNT / setPcts[button.semantic_id];
165
+ adjustedDistance = Math.min(adjustedDistance, adjustedDistance * discount);
166
+ }
167
+ }
168
+ // Apply clone_id discounts
169
+ if (button.clone_id) {
170
+ if (boardPcts[button.clone_id]) {
171
+ const discount = exports.EFFORT_CONSTANTS.SAME_LOCATION_AS_PRIOR_DISCOUNT / boardPcts[button.clone_id];
172
+ adjustedDistance = Math.min(adjustedDistance, adjustedDistance * discount);
173
+ }
174
+ else if (setPcts[button.clone_id]) {
175
+ const discount = exports.EFFORT_CONSTANTS.RECOGNIZABLE_CLONE_FROM_OTHER_DISCOUNT / setPcts[button.clone_id];
176
+ adjustedDistance = Math.min(adjustedDistance, adjustedDistance * discount);
177
+ }
178
+ }
179
+ return adjustedDistance;
180
+ }
181
+ /**
182
+ * Check if visual scan should be skipped (button close to previous)
183
+ *
184
+ * @param distance - Distance from previous button
185
+ * @returns True if close enough to skip full visual scan
186
+ */
187
+ function shouldSkipVisualScan(distance) {
188
+ return distance < exports.EFFORT_CONSTANTS.DISTANCE_THRESHOLD_TO_SKIP_VISUAL_SCAN;
189
+ }
190
+ /**
191
+ * Calculate local scan effort when buttons are close
192
+ *
193
+ * @param distance - Distance between buttons
194
+ * @returns Local scan effort
195
+ */
196
+ function localScanEffort(distance) {
197
+ return distance * exports.EFFORT_CONSTANTS.SKIPPED_VISUAL_SCAN_DISTANCE_MULTIPLIER;
198
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * AAC Metrics Module
3
+ *
4
+ * Comprehensive metrics analysis for AAC board sets including:
5
+ * - Effort score calculation with motor planning
6
+ * - Vocabulary coverage analysis
7
+ * - Sentence construction evaluation
8
+ * - Comparative analysis between board sets
9
+ */
10
+ export { MetricsCalculator } from './core';
11
+ export { VocabularyAnalyzer } from './vocabulary';
12
+ export { SentenceAnalyzer } from './sentence';
13
+ export { ComparisonAnalyzer } from './comparison';
14
+ export * from './types';
15
+ export * from './effort';
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ /**
3
+ * AAC Metrics Module
4
+ *
5
+ * Comprehensive metrics analysis for AAC board sets including:
6
+ * - Effort score calculation with motor planning
7
+ * - Vocabulary coverage analysis
8
+ * - Sentence construction evaluation
9
+ * - Comparative analysis between board sets
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
23
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.ComparisonAnalyzer = exports.SentenceAnalyzer = exports.VocabularyAnalyzer = exports.MetricsCalculator = void 0;
27
+ var core_1 = require("./core");
28
+ Object.defineProperty(exports, "MetricsCalculator", { enumerable: true, get: function () { return core_1.MetricsCalculator; } });
29
+ var vocabulary_1 = require("./vocabulary");
30
+ Object.defineProperty(exports, "VocabularyAnalyzer", { enumerable: true, get: function () { return vocabulary_1.VocabularyAnalyzer; } });
31
+ var sentence_1 = require("./sentence");
32
+ Object.defineProperty(exports, "SentenceAnalyzer", { enumerable: true, get: function () { return sentence_1.SentenceAnalyzer; } });
33
+ var comparison_1 = require("./comparison");
34
+ Object.defineProperty(exports, "ComparisonAnalyzer", { enumerable: true, get: function () { return comparison_1.ComparisonAnalyzer; } });
35
+ __exportStar(require("./types"), exports);
36
+ __exportStar(require("./effort"), exports);
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Sentence Construction Analysis
3
+ *
4
+ * Calculates the effort required to construct test sentences
5
+ * from the AAC board set, including spelling fallback for missing words.
6
+ */
7
+ import { MetricsResult } from './types';
8
+ export interface SentenceAnalysis {
9
+ sentence: string;
10
+ words: string[];
11
+ effort: number;
12
+ total_effort: number;
13
+ typing: boolean;
14
+ missing_words: string[];
15
+ word_efforts: Array<{
16
+ word: string;
17
+ effort: number;
18
+ typed: boolean;
19
+ }>;
20
+ }
21
+ export declare class SentenceAnalyzer {
22
+ /**
23
+ * Analyze effort to construct a set of test sentences
24
+ */
25
+ analyzeSentences(metrics: MetricsResult, sentences: string[][]): SentenceAnalysis[];
26
+ /**
27
+ * Analyze effort to construct a single sentence
28
+ */
29
+ analyzeSentence(metrics: MetricsResult, words: string[]): SentenceAnalysis;
30
+ /**
31
+ * Reconstruct sentence from word array
32
+ */
33
+ private reconstructSentence;
34
+ /**
35
+ * Calculate statistics across all sentences
36
+ */
37
+ calculateStatistics(analyses: SentenceAnalysis[]): {
38
+ total_sentences: number;
39
+ sentences_requiring_typing: number;
40
+ sentences_without_typing: number;
41
+ average_effort: number;
42
+ min_effort: number;
43
+ max_effort: number;
44
+ median_effort: number;
45
+ total_words: number;
46
+ words_requiring_typing: number;
47
+ typing_percent: number;
48
+ };
49
+ }
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * Sentence Construction Analysis
4
+ *
5
+ * Calculates the effort required to construct test sentences
6
+ * from the AAC board set, including spelling fallback for missing words.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.SentenceAnalyzer = void 0;
10
+ const effort_1 = require("./effort");
11
+ class SentenceAnalyzer {
12
+ /**
13
+ * Analyze effort to construct a set of test sentences
14
+ */
15
+ analyzeSentences(metrics, sentences) {
16
+ return sentences.map((words) => this.analyzeSentence(metrics, words));
17
+ }
18
+ /**
19
+ * Analyze effort to construct a single sentence
20
+ */
21
+ analyzeSentence(metrics, words) {
22
+ const wordEfforts = [];
23
+ let totalEffort = 0;
24
+ let typing = false;
25
+ const missingWords = [];
26
+ // Create word lookup map
27
+ const wordMap = new Map();
28
+ metrics.buttons.forEach((btn) => {
29
+ const existing = wordMap.get(btn.label.toLowerCase());
30
+ if (!existing || btn.effort < existing.effort) {
31
+ wordMap.set(btn.label.toLowerCase(), { effort: btn.effort });
32
+ }
33
+ });
34
+ // Calculate effort for each word
35
+ words.forEach((word) => {
36
+ const lowerWord = word.toLowerCase();
37
+ const found = wordMap.get(lowerWord);
38
+ if (found) {
39
+ wordEfforts.push({ word, effort: found.effort, typed: false });
40
+ totalEffort += found.effort;
41
+ }
42
+ else {
43
+ // Word not found - use spelling effort
44
+ const spellEffort = (0, effort_1.spellingEffort)(word);
45
+ wordEfforts.push({ word, effort: spellEffort, typed: true });
46
+ totalEffort += spellEffort;
47
+ typing = true;
48
+ missingWords.push(word);
49
+ }
50
+ });
51
+ const averageEffort = totalEffort / words.length;
52
+ // Reconstruct sentence for display
53
+ const sentence = this.reconstructSentence(words);
54
+ return {
55
+ sentence,
56
+ words,
57
+ effort: averageEffort,
58
+ total_effort: totalEffort,
59
+ typing,
60
+ missing_words: missingWords,
61
+ word_efforts: wordEfforts,
62
+ };
63
+ }
64
+ /**
65
+ * Reconstruct sentence from word array
66
+ */
67
+ reconstructSentence(words) {
68
+ return words
69
+ .map((word, idx) => {
70
+ // Capitalize first word
71
+ if (idx === 0) {
72
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
73
+ }
74
+ return word.toLowerCase();
75
+ })
76
+ .join(' ');
77
+ }
78
+ /**
79
+ * Calculate statistics across all sentences
80
+ */
81
+ calculateStatistics(analyses) {
82
+ const totalSentences = analyses.length;
83
+ const sentencesRequiringTyping = analyses.filter((a) => a.typing).length;
84
+ const sentencesWithoutTyping = totalSentences - sentencesRequiringTyping;
85
+ const efforts = analyses.map((a) => a.effort);
86
+ const averageEffort = efforts.reduce((sum, e) => sum + e, 0) / efforts.length;
87
+ const minEffort = Math.min(...efforts);
88
+ const maxEffort = Math.max(...efforts);
89
+ // Calculate median
90
+ const sortedEfforts = [...efforts].sort((a, b) => a - b);
91
+ const medianEffort = sortedEfforts.length % 2 === 0
92
+ ? (sortedEfforts[sortedEfforts.length / 2 - 1] + sortedEfforts[sortedEfforts.length / 2]) /
93
+ 2
94
+ : sortedEfforts[Math.floor(sortedEfforts.length / 2)];
95
+ const totalWords = analyses.reduce((sum, a) => sum + a.words.length, 0);
96
+ const wordsRequiringTyping = analyses.reduce((sum, a) => sum + a.missing_words.length, 0);
97
+ const typingPercent = (wordsRequiringTyping / totalWords) * 100;
98
+ return {
99
+ total_sentences: totalSentences,
100
+ sentences_requiring_typing: sentencesRequiringTyping,
101
+ sentences_without_typing: sentencesWithoutTyping,
102
+ average_effort: averageEffort,
103
+ min_effort: minEffort,
104
+ max_effort: maxEffort,
105
+ median_effort: medianEffort,
106
+ total_words: totalWords,
107
+ words_requiring_typing: wordsRequiringTyping,
108
+ typing_percent: typingPercent,
109
+ };
110
+ }
111
+ }
112
+ exports.SentenceAnalyzer = SentenceAnalyzer;
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Metrics Types and Interfaces
3
+ *
4
+ * Defines the data structures used for AAC metrics analysis
5
+ */
6
+ /**
7
+ * Button-level metrics result
8
+ */
9
+ export interface ButtonMetrics {
10
+ id: string;
11
+ label: string;
12
+ level: number;
13
+ effort: number;
14
+ count?: number;
15
+ semantic_id?: string;
16
+ clone_id?: string;
17
+ temporary_home_id?: string;
18
+ comp_level?: number;
19
+ comp_effort?: number;
20
+ }
21
+ /**
22
+ * Board/page level analysis result
23
+ */
24
+ export interface BoardAnalysis {
25
+ boardId: string;
26
+ level: number;
27
+ entryX: number;
28
+ entryY: number;
29
+ priorEffort?: number;
30
+ temporaryHomeId?: string;
31
+ }
32
+ /**
33
+ * Metrics analysis result
34
+ */
35
+ export interface MetricsResult {
36
+ analysis_version: string;
37
+ locale: string;
38
+ total_boards: number;
39
+ total_buttons: number;
40
+ total_words: number;
41
+ reference_counts: {
42
+ [id: string]: number;
43
+ };
44
+ grid: {
45
+ rows: number;
46
+ columns: number;
47
+ };
48
+ buttons: ButtonMetrics[];
49
+ levels: {
50
+ [level: number]: ButtonMetrics[];
51
+ };
52
+ alternates?: {
53
+ [boardId: string]: AlternateBoardMetrics;
54
+ };
55
+ obfset?: any;
56
+ }
57
+ /**
58
+ * Alternate board metrics (for temporary home navigation)
59
+ */
60
+ export interface AlternateBoardMetrics {
61
+ buttons: ButtonMetrics[];
62
+ levels: {
63
+ [level: number]: ButtonMetrics[];
64
+ };
65
+ }
66
+ /**
67
+ * Comparison result between two board sets
68
+ */
69
+ export interface ComparisonResult extends MetricsResult {
70
+ target_effort_score: number;
71
+ comp_boards: number;
72
+ comp_buttons: number;
73
+ comp_words: number;
74
+ comp_grid: {
75
+ rows: number;
76
+ columns: number;
77
+ };
78
+ comp_effort_score: number;
79
+ missing_words: string[];
80
+ extra_words: string[];
81
+ overlapping_words: string[];
82
+ missing: {
83
+ [listId: string]: {
84
+ name: string;
85
+ list: string[];
86
+ };
87
+ };
88
+ high_effort_words: string[];
89
+ low_effort_words: string[];
90
+ cores: {
91
+ [listId: string]: {
92
+ name: string;
93
+ list: string[];
94
+ average_effort: number;
95
+ comp_effort: number;
96
+ };
97
+ };
98
+ care_components: {
99
+ core: number;
100
+ comp_core: number;
101
+ sentences: number;
102
+ comp_sentences: number;
103
+ fringe: number;
104
+ comp_fringe: number;
105
+ common_fringe: number;
106
+ comp_common_fringe: number;
107
+ };
108
+ sentences: SentenceAnalysis[];
109
+ fringe_words: FringeWord[];
110
+ common_fringe_words: FringeWord[];
111
+ }
112
+ /**
113
+ * Sentence construction analysis
114
+ */
115
+ export interface SentenceAnalysis {
116
+ sentence: string;
117
+ words: string[];
118
+ effort: number;
119
+ typing: boolean;
120
+ comp_effort: number;
121
+ comp_typing: boolean;
122
+ }
123
+ /**
124
+ * Fringe vocabulary word analysis
125
+ */
126
+ export interface FringeWord {
127
+ word: string;
128
+ effort: number;
129
+ comp_effort: number;
130
+ }
131
+ /**
132
+ * Core vocabulary list definition
133
+ */
134
+ export interface CoreList {
135
+ id: string;
136
+ name: string;
137
+ url?: string;
138
+ locale: string;
139
+ words: string[];
140
+ }
141
+ /**
142
+ * Common words reference data
143
+ */
144
+ export interface CommonWordsData {
145
+ version: string;
146
+ files: string[];
147
+ words: string[];
148
+ efforts: {
149
+ [word: string]: number;
150
+ };
151
+ }
152
+ /**
153
+ * Synonym mappings
154
+ */
155
+ export interface SynonymsData {
156
+ [word: string]: string[];
157
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * Metrics Types and Interfaces
4
+ *
5
+ * Defines the data structures used for AAC metrics analysis
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Vocabulary Coverage Analysis
3
+ *
4
+ * Analyzes how well an AAC board set covers core vocabulary
5
+ * and identifies missing/extra words compared to reference lists.
6
+ */
7
+ import { MetricsResult } from './types';
8
+ import { ReferenceLoader } from '../reference/index';
9
+ export interface VocabularyAnalysis {
10
+ core_coverage: {
11
+ [listId: string]: {
12
+ name: string;
13
+ total_words: number;
14
+ covered: number;
15
+ missing: number;
16
+ coverage_percent: number;
17
+ missing_words: string[];
18
+ average_effort: number;
19
+ };
20
+ };
21
+ total_unique_words: number;
22
+ words_with_effort: number;
23
+ words_requiring_spelling: number;
24
+ extra_words: string[];
25
+ high_effort_words: Array<{
26
+ word: string;
27
+ effort: number;
28
+ }>;
29
+ low_effort_words: Array<{
30
+ word: string;
31
+ effort: number;
32
+ }>;
33
+ }
34
+ export declare class VocabularyAnalyzer {
35
+ private referenceLoader;
36
+ constructor(referenceLoader?: ReferenceLoader);
37
+ /**
38
+ * Analyze vocabulary coverage against core lists
39
+ */
40
+ analyze(metrics: MetricsResult, options?: {
41
+ locale?: string;
42
+ highEffortThreshold?: number;
43
+ lowEffortThreshold?: number;
44
+ }): VocabularyAnalysis;
45
+ /**
46
+ * Analyze coverage for a single core list
47
+ */
48
+ private analyzeCoreList;
49
+ /**
50
+ * Calculate coverage percentage for a specific word list
51
+ */
52
+ calculateCoverage(wordList: string[], metrics: MetricsResult): {
53
+ covered: string[];
54
+ missing: string[];
55
+ coverage_percent: number;
56
+ };
57
+ /**
58
+ * Get effort for a word, or calculate spelling effort if missing
59
+ */
60
+ getWordEffort(word: string, metrics: MetricsResult): number;
61
+ /**
62
+ * Check if a word is in the board set
63
+ */
64
+ hasWord(word: string, metrics: MetricsResult): boolean;
65
+ }