@willwade/aac-processors 0.0.15 → 0.0.17
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 +17 -8
- package/dist/core/treeStructure.d.ts +1 -0
- package/dist/processors/gridset/commands.js +15 -0
- package/dist/processors/gridset/pluginTypes.js +4 -4
- package/dist/processors/gridsetProcessor.d.ts +4 -0
- package/dist/processors/gridsetProcessor.js +315 -47
- package/dist/processors/snapProcessor.js +105 -9
- package/dist/processors/touchchatProcessor.js +33 -13
- package/dist/types/aac.d.ts +13 -3
- package/dist/types/aac.js +6 -2
- package/dist/utilities/analytics/metrics/comparison.d.ts +3 -1
- package/dist/utilities/analytics/metrics/comparison.js +189 -42
- package/dist/utilities/analytics/metrics/core.d.ts +7 -2
- package/dist/utilities/analytics/metrics/core.js +323 -197
- package/dist/utilities/analytics/metrics/effort.d.ts +23 -3
- package/dist/utilities/analytics/metrics/effort.js +31 -5
- package/dist/utilities/analytics/metrics/sentence.js +17 -4
- package/dist/utilities/analytics/metrics/types.d.ts +61 -0
- package/dist/utilities/analytics/metrics/vocabulary.js +1 -1
- package/dist/utilities/analytics/reference/index.d.ts +6 -0
- package/dist/utilities/analytics/reference/index.js +29 -1
- package/dist/utilities/translation/translationProcessor.d.ts +2 -1
- package/dist/utilities/translation/translationProcessor.js +5 -2
- package/package.json +1 -1
|
@@ -10,31 +10,40 @@ exports.ComparisonAnalyzer = void 0;
|
|
|
10
10
|
const sentence_1 = require("./sentence");
|
|
11
11
|
const vocabulary_1 = require("./vocabulary");
|
|
12
12
|
const index_1 = require("../reference/index");
|
|
13
|
+
const effort_1 = require("./effort");
|
|
13
14
|
class ComparisonAnalyzer {
|
|
14
15
|
constructor() {
|
|
15
16
|
this.vocabAnalyzer = new vocabulary_1.VocabularyAnalyzer();
|
|
16
17
|
this.sentenceAnalyzer = new sentence_1.SentenceAnalyzer();
|
|
17
18
|
this.referenceLoader = new index_1.ReferenceLoader();
|
|
18
19
|
}
|
|
20
|
+
normalize(word) {
|
|
21
|
+
return word
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
.trim()
|
|
24
|
+
.replace(/[.?!,]/g, '');
|
|
25
|
+
}
|
|
19
26
|
/**
|
|
20
27
|
* Compare two board sets
|
|
21
28
|
*/
|
|
22
29
|
compare(targetResult, compareResult, options) {
|
|
23
30
|
// Create base result from target
|
|
24
31
|
const baseResult = { ...targetResult };
|
|
25
|
-
// Create word maps
|
|
32
|
+
// Create word maps with normalized keys
|
|
26
33
|
const targetWords = new Map();
|
|
27
34
|
targetResult.buttons.forEach((btn) => {
|
|
28
|
-
const
|
|
35
|
+
const key = this.normalize(btn.label);
|
|
36
|
+
const existing = targetWords.get(key);
|
|
29
37
|
if (!existing || btn.effort < existing.effort) {
|
|
30
|
-
targetWords.set(
|
|
38
|
+
targetWords.set(key, btn);
|
|
31
39
|
}
|
|
32
40
|
});
|
|
33
41
|
const compareWords = new Map();
|
|
34
42
|
compareResult.buttons.forEach((btn) => {
|
|
35
|
-
const
|
|
43
|
+
const key = this.normalize(btn.label);
|
|
44
|
+
const existing = compareWords.get(key);
|
|
36
45
|
if (!existing || btn.effort < existing.effort) {
|
|
37
|
-
compareWords.set(
|
|
46
|
+
compareWords.set(key, btn);
|
|
38
47
|
}
|
|
39
48
|
});
|
|
40
49
|
// Find missing/extra/overlapping words
|
|
@@ -62,7 +71,8 @@ class ComparisonAnalyzer {
|
|
|
62
71
|
overlappingWords.sort((a, b) => a.localeCompare(b));
|
|
63
72
|
// Add comparison metrics to buttons
|
|
64
73
|
const enrichedButtons = targetResult.buttons.map((btn) => {
|
|
65
|
-
const
|
|
74
|
+
const key = this.normalize(btn.label);
|
|
75
|
+
const compBtn = compareWords.get(key);
|
|
66
76
|
return {
|
|
67
77
|
...btn,
|
|
68
78
|
comp_level: compBtn?.level,
|
|
@@ -70,7 +80,7 @@ class ComparisonAnalyzer {
|
|
|
70
80
|
};
|
|
71
81
|
});
|
|
72
82
|
// Calculate CARE components
|
|
73
|
-
const careComponents = this.calculateCareComponents(targetResult, compareResult, overlappingWords);
|
|
83
|
+
const careComponents = this.calculateCareComponents(targetResult, compareResult, overlappingWords, options);
|
|
74
84
|
// Analyze high/low effort words
|
|
75
85
|
const highEffortWords = [];
|
|
76
86
|
const lowEffortWords = [];
|
|
@@ -124,8 +134,9 @@ class ComparisonAnalyzer {
|
|
|
124
134
|
let targetCovered = 0;
|
|
125
135
|
let compareCovered = 0;
|
|
126
136
|
list.words.forEach((word) => {
|
|
127
|
-
const
|
|
128
|
-
const
|
|
137
|
+
const key = this.normalize(word);
|
|
138
|
+
const targetBtn = targetWords.get(key);
|
|
139
|
+
const compareBtn = compareWords.get(key);
|
|
129
140
|
if (targetBtn) {
|
|
130
141
|
targetCovered++;
|
|
131
142
|
targetTotal += targetBtn.effort;
|
|
@@ -140,6 +151,9 @@ class ComparisonAnalyzer {
|
|
|
140
151
|
list: list.words,
|
|
141
152
|
average_effort: targetCovered > 0 ? targetTotal / targetCovered : 0,
|
|
142
153
|
comp_effort: compareCovered > 0 ? compareTotal / compareCovered : 0,
|
|
154
|
+
target_covered: targetCovered,
|
|
155
|
+
compare_covered: compareCovered,
|
|
156
|
+
total_words: list.words.length,
|
|
143
157
|
};
|
|
144
158
|
});
|
|
145
159
|
// Analyze missing from specific lists
|
|
@@ -147,7 +161,8 @@ class ComparisonAnalyzer {
|
|
|
147
161
|
coreLists.forEach((list) => {
|
|
148
162
|
const listMissing = [];
|
|
149
163
|
list.words.forEach((word) => {
|
|
150
|
-
|
|
164
|
+
const key = this.normalize(word);
|
|
165
|
+
if (!targetWords.has(key)) {
|
|
151
166
|
listMissing.push(word);
|
|
152
167
|
}
|
|
153
168
|
});
|
|
@@ -172,6 +187,13 @@ class ComparisonAnalyzer {
|
|
|
172
187
|
comp_words: compareResult.total_words,
|
|
173
188
|
comp_grid: compareResult.grid,
|
|
174
189
|
comp_effort_score: this.calculateEffortScore(compareResult),
|
|
190
|
+
comp_spelling_effort_base: compareResult.spelling_effort_base,
|
|
191
|
+
comp_spelling_effort_per_letter: compareResult.spelling_effort_per_letter,
|
|
192
|
+
comp_spelling_page_id: compareResult.spelling_page_id,
|
|
193
|
+
has_dynamic_prediction: targetResult.has_dynamic_prediction,
|
|
194
|
+
prediction_page_id: targetResult.prediction_page_id,
|
|
195
|
+
comp_has_dynamic_prediction: compareResult.has_dynamic_prediction,
|
|
196
|
+
comp_prediction_page_id: compareResult.prediction_page_id,
|
|
175
197
|
// Vocabulary comparison
|
|
176
198
|
missing_words: missingWords,
|
|
177
199
|
extra_words: extraWords,
|
|
@@ -195,78 +217,198 @@ class ComparisonAnalyzer {
|
|
|
195
217
|
/**
|
|
196
218
|
* Calculate CARE component scores
|
|
197
219
|
*/
|
|
198
|
-
calculateCareComponents(targetResult, compareResult, _overlappingWords) {
|
|
199
|
-
//
|
|
220
|
+
calculateCareComponents(targetResult, compareResult, _overlappingWords, options) {
|
|
221
|
+
// Load common words with baseline efforts (matching Ruby line 527-534)
|
|
222
|
+
const commonWordsData = this.referenceLoader.loadCommonWords();
|
|
223
|
+
const commonWords = new Map();
|
|
224
|
+
commonWordsData.words.forEach((word) => {
|
|
225
|
+
commonWords.set(word.toLowerCase(), commonWordsData.efforts[word] || 0);
|
|
226
|
+
});
|
|
227
|
+
// Determine prediction settings (default: use common words efforts, not prediction)
|
|
228
|
+
const usePrediction = options?.usePrediction || false; // Default FALSE (use common words)
|
|
229
|
+
const predictionSelections = options?.predictionSelections || 1.5;
|
|
230
|
+
const debugMode = process.env.DEBUG_METRICS === 'true';
|
|
231
|
+
// Helper function to calculate fallback effort
|
|
232
|
+
const getFallbackEffort = (word, hasPrediction, spellingBaseEffort) => {
|
|
233
|
+
const wordLower = word.toLowerCase();
|
|
234
|
+
// Check common words efforts first (matching Ruby line 533)
|
|
235
|
+
if (commonWords.has(wordLower)) {
|
|
236
|
+
const effort = commonWords.get(wordLower);
|
|
237
|
+
return effort !== undefined ? effort : (0, effort_1.spellingEffort)(word, 10, 2.5);
|
|
238
|
+
}
|
|
239
|
+
// If usePrediction is true and prediction is available, use prediction
|
|
240
|
+
if (usePrediction && hasPrediction && spellingBaseEffort !== undefined) {
|
|
241
|
+
return (0, effort_1.predictionEffort)(spellingBaseEffort, 2.5, predictionSelections, 2);
|
|
242
|
+
}
|
|
243
|
+
// Fallback to manual spelling (matching Ruby spelling_effort: 10 + word.length * 2.5)
|
|
244
|
+
return (0, effort_1.spellingEffort)(word, 10, 2.5);
|
|
245
|
+
};
|
|
246
|
+
// Debug: Check settings
|
|
247
|
+
const targetHasPrediction = targetResult.has_dynamic_prediction && targetResult.spelling_effort_base !== undefined;
|
|
248
|
+
const _compareHasPrediction = compareResult.has_dynamic_prediction && compareResult.spelling_effort_base !== undefined;
|
|
249
|
+
if (debugMode) {
|
|
250
|
+
console.log(`\n🔍 DEBUG Fallback Effort Settings:`);
|
|
251
|
+
console.log(` Common words loaded: ${commonWords.size}`);
|
|
252
|
+
console.log(` usePrediction option: ${usePrediction}`);
|
|
253
|
+
console.log(` Target has prediction capability: ${targetHasPrediction}`);
|
|
254
|
+
console.log(` Target spelling_base: ${targetResult.spelling_effort_base?.toFixed(2) || 'undefined'}`);
|
|
255
|
+
}
|
|
256
|
+
// Create word maps with normalized keys
|
|
200
257
|
const targetWords = new Map();
|
|
201
258
|
targetResult.buttons.forEach((btn) => {
|
|
202
|
-
const
|
|
259
|
+
const key = this.normalize(btn.label);
|
|
260
|
+
const existing = targetWords.get(key);
|
|
203
261
|
if (!existing || btn.effort < existing.effort) {
|
|
204
|
-
targetWords.set(
|
|
262
|
+
targetWords.set(key, btn);
|
|
205
263
|
}
|
|
206
264
|
});
|
|
207
265
|
const compareWords = new Map();
|
|
208
266
|
compareResult.buttons.forEach((btn) => {
|
|
209
|
-
const
|
|
267
|
+
const key = this.normalize(btn.label);
|
|
268
|
+
const existing = compareWords.get(key);
|
|
210
269
|
if (!existing || btn.effort < existing.effort) {
|
|
211
|
-
compareWords.set(
|
|
270
|
+
compareWords.set(key, btn);
|
|
212
271
|
}
|
|
213
272
|
});
|
|
214
273
|
// Load reference data
|
|
215
274
|
const coreLists = this.referenceLoader.loadCoreLists();
|
|
216
275
|
const fringe = this.referenceLoader.loadFringe();
|
|
276
|
+
const commonFringe = this.referenceLoader.loadCommonFringe();
|
|
217
277
|
const sentences = this.referenceLoader.loadSentences();
|
|
218
|
-
// Calculate core coverage
|
|
278
|
+
// Calculate core coverage and effort (matching Ruby lines 609-647)
|
|
219
279
|
let coreCount = 0;
|
|
220
280
|
let compCoreCount = 0;
|
|
281
|
+
let targetCoreEffort = 0;
|
|
282
|
+
let compCoreEffort = 0;
|
|
221
283
|
const allCoreWords = new Set();
|
|
222
284
|
coreLists.forEach((list) => {
|
|
223
285
|
list.words.forEach((word) => allCoreWords.add(word.toLowerCase()));
|
|
224
286
|
});
|
|
225
287
|
allCoreWords.forEach((word) => {
|
|
226
|
-
|
|
288
|
+
const key = this.normalize(word);
|
|
289
|
+
const targetBtn = targetWords.get(key);
|
|
290
|
+
const compareBtn = compareWords.get(key);
|
|
291
|
+
if (targetBtn) {
|
|
227
292
|
coreCount++;
|
|
228
|
-
|
|
293
|
+
targetCoreEffort += targetBtn.effort;
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
// Fallback to spelling or prediction effort
|
|
297
|
+
targetCoreEffort += getFallbackEffort(word, targetResult.has_dynamic_prediction || false, targetResult.spelling_effort_base);
|
|
298
|
+
}
|
|
299
|
+
if (compareBtn) {
|
|
229
300
|
compCoreCount++;
|
|
301
|
+
compCoreEffort += compareBtn.effort;
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
compCoreEffort += getFallbackEffort(word, compareResult.has_dynamic_prediction || false, compareResult.spelling_effort_base);
|
|
305
|
+
}
|
|
230
306
|
});
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
307
|
+
const avgCoreEffort = allCoreWords.size > 0 ? targetCoreEffort / allCoreWords.size : 0;
|
|
308
|
+
const avgCompCoreEffort = allCoreWords.size > 0 ? compCoreEffort / allCoreWords.size : 0;
|
|
309
|
+
// Calculate core component scores (matching Ruby lines 644-647)
|
|
310
|
+
const coreScore = avgCoreEffort * 5.0;
|
|
311
|
+
const compCoreScore = avgCompCoreEffort * 5.0;
|
|
312
|
+
// Calculate sentence construction effort (matching Ruby lines 654-668)
|
|
313
|
+
const sentenceEfforts = [];
|
|
314
|
+
const compSentenceEfforts = [];
|
|
235
315
|
sentences.forEach((words) => {
|
|
316
|
+
let targetSentenceEffort = 0;
|
|
317
|
+
let compSentenceEffort = 0;
|
|
236
318
|
words.forEach((word) => {
|
|
237
|
-
const
|
|
238
|
-
const
|
|
319
|
+
const key = this.normalize(word);
|
|
320
|
+
const targetBtn = targetWords.get(key);
|
|
321
|
+
const compareBtn = compareWords.get(key);
|
|
239
322
|
if (targetBtn) {
|
|
240
|
-
|
|
323
|
+
targetSentenceEffort += targetBtn.effort;
|
|
241
324
|
}
|
|
242
325
|
else {
|
|
243
|
-
|
|
326
|
+
targetSentenceEffort += getFallbackEffort(word, targetResult.has_dynamic_prediction || false, targetResult.spelling_effort_base);
|
|
244
327
|
}
|
|
245
328
|
if (compareBtn) {
|
|
246
329
|
compSentenceEffort += compareBtn.effort;
|
|
247
330
|
}
|
|
248
331
|
else {
|
|
249
|
-
compSentenceEffort +=
|
|
332
|
+
compSentenceEffort += getFallbackEffort(word, compareResult.has_dynamic_prediction || false, compareResult.spelling_effort_base);
|
|
250
333
|
}
|
|
251
|
-
sentenceWordCount++;
|
|
252
334
|
});
|
|
335
|
+
// Average effort per sentence (matching Ruby line 657)
|
|
336
|
+
sentenceEfforts.push(targetSentenceEffort / words.length);
|
|
337
|
+
compSentenceEfforts.push(compSentenceEffort / words.length);
|
|
253
338
|
});
|
|
254
|
-
const avgSentenceEffort =
|
|
255
|
-
|
|
256
|
-
|
|
339
|
+
const avgSentenceEffort = sentenceEfforts.length > 0
|
|
340
|
+
? sentenceEfforts.reduce((a, b) => a + b, 0) / sentenceEfforts.length
|
|
341
|
+
: 0;
|
|
342
|
+
const compAvgSentenceEffort = compSentenceEfforts.length > 0
|
|
343
|
+
? compSentenceEfforts.reduce((a, b) => a + b, 0) / compSentenceEfforts.length
|
|
344
|
+
: 0;
|
|
345
|
+
// Sentence component scores (matching Ruby line 665-668)
|
|
346
|
+
const sentenceScore = avgSentenceEffort * 3.0;
|
|
347
|
+
const compSentenceScore = compAvgSentenceEffort * 3.0;
|
|
348
|
+
// Calculate fringe effort (matching Ruby lines 670-687)
|
|
349
|
+
const fringeEfforts = [];
|
|
350
|
+
const compFringeEfforts = [];
|
|
257
351
|
let fringeCount = 0;
|
|
258
352
|
let compFringeCount = 0;
|
|
259
|
-
let commonFringeCount = 0;
|
|
260
353
|
fringe.forEach((word) => {
|
|
261
|
-
const
|
|
262
|
-
const
|
|
263
|
-
|
|
354
|
+
const key = this.normalize(word);
|
|
355
|
+
const targetBtn = targetWords.get(key);
|
|
356
|
+
const compareBtn = compareWords.get(key);
|
|
357
|
+
if (targetBtn) {
|
|
358
|
+
fringeEfforts.push(targetBtn.effort);
|
|
264
359
|
fringeCount++;
|
|
265
|
-
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
fringeEfforts.push(getFallbackEffort(word, targetResult.has_dynamic_prediction || false, targetResult.spelling_effort_base));
|
|
363
|
+
}
|
|
364
|
+
if (compareBtn) {
|
|
365
|
+
compFringeEfforts.push(compareBtn.effort);
|
|
266
366
|
compFringeCount++;
|
|
267
|
-
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
compFringeEfforts.push(getFallbackEffort(word, compareResult.has_dynamic_prediction || false, compareResult.spelling_effort_base));
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
const avgFringeEffort = fringeEfforts.length > 0
|
|
373
|
+
? fringeEfforts.reduce((a, b) => a + b, 0) / fringeEfforts.length
|
|
374
|
+
: 0;
|
|
375
|
+
const avgCompFringeEffort = compFringeEfforts.length > 0
|
|
376
|
+
? compFringeEfforts.reduce((a, b) => a + b, 0) / compFringeEfforts.length
|
|
377
|
+
: 0;
|
|
378
|
+
// Fringe component scores (matching Ruby line 684-687)
|
|
379
|
+
const fringeScore = avgFringeEffort * 2.0;
|
|
380
|
+
const compFringeScore = avgCompFringeEffort * 2.0;
|
|
381
|
+
// Calculate common fringe effort (matching Ruby lines 689-705)
|
|
382
|
+
const commonFringeEfforts = [];
|
|
383
|
+
const compCommonFringeEfforts = [];
|
|
384
|
+
let commonFringeCount = 0;
|
|
385
|
+
commonFringe.forEach((word) => {
|
|
386
|
+
const key = this.normalize(word);
|
|
387
|
+
const targetBtn = targetWords.get(key);
|
|
388
|
+
const compareBtn = compareWords.get(key);
|
|
389
|
+
if (targetBtn && compareBtn) {
|
|
390
|
+
commonFringeEfforts.push(targetBtn.effort);
|
|
391
|
+
compCommonFringeEfforts.push(compareBtn.effort);
|
|
268
392
|
commonFringeCount++;
|
|
393
|
+
}
|
|
269
394
|
});
|
|
395
|
+
const avgCommonFringeEffort = commonFringeEfforts.length > 0
|
|
396
|
+
? commonFringeEfforts.reduce((a, b) => a + b, 0) / commonFringeEfforts.length
|
|
397
|
+
: 0;
|
|
398
|
+
const avgCompCommonFringeEffort = compCommonFringeEfforts.length > 0
|
|
399
|
+
? compCommonFringeEfforts.reduce((a, b) => a + b, 0) / compCommonFringeEfforts.length
|
|
400
|
+
: 0;
|
|
401
|
+
// Common fringe component scores (matching Ruby line 702-705)
|
|
402
|
+
const commonFringeScore = avgCommonFringeEffort * 1.0;
|
|
403
|
+
const compCommonFringeScore = avgCompCommonFringeEffort * 1.0;
|
|
404
|
+
// Calculate total CARE effort tally (matching Ruby lines 707-708)
|
|
405
|
+
const PLACEHOLDER = 70;
|
|
406
|
+
const targetEffortTally = coreScore + sentenceScore + fringeScore + commonFringeScore + PLACEHOLDER;
|
|
407
|
+
const compEffortTally = compCoreScore + compSentenceScore + compFringeScore + compCommonFringeScore + PLACEHOLDER;
|
|
408
|
+
// Calculate final CARE scores (matching Ruby line 710-711)
|
|
409
|
+
// res[:target_effort_score] = [0.0, 350.0 - target_effort_tally].max
|
|
410
|
+
const careScore = Math.max(0, 350.0 - targetEffortTally);
|
|
411
|
+
const compCareScore = Math.max(0, 350.0 - compEffortTally);
|
|
270
412
|
return {
|
|
271
413
|
core: coreCount,
|
|
272
414
|
comp_core: compCoreCount,
|
|
@@ -276,6 +418,9 @@ class ComparisonAnalyzer {
|
|
|
276
418
|
comp_fringe: compFringeCount,
|
|
277
419
|
common_fringe: commonFringeCount,
|
|
278
420
|
comp_common_fringe: commonFringeCount,
|
|
421
|
+
// New composite CARE scores
|
|
422
|
+
care_score: careScore,
|
|
423
|
+
comp_care_score: compCareScore,
|
|
279
424
|
};
|
|
280
425
|
}
|
|
281
426
|
/**
|
|
@@ -285,8 +430,9 @@ class ComparisonAnalyzer {
|
|
|
285
430
|
const fringe = this.referenceLoader.loadFringe();
|
|
286
431
|
const result = [];
|
|
287
432
|
fringe.forEach((word) => {
|
|
288
|
-
const
|
|
289
|
-
const
|
|
433
|
+
const key = this.normalize(word);
|
|
434
|
+
const targetBtn = targetWords.get(key);
|
|
435
|
+
const compareBtn = compareWords.get(key);
|
|
290
436
|
if (targetBtn) {
|
|
291
437
|
result.push({
|
|
292
438
|
word,
|
|
@@ -305,8 +451,9 @@ class ComparisonAnalyzer {
|
|
|
305
451
|
const fringe = this.referenceLoader.loadFringe();
|
|
306
452
|
const result = [];
|
|
307
453
|
fringe.forEach((word) => {
|
|
308
|
-
const
|
|
309
|
-
const
|
|
454
|
+
const key = this.normalize(word);
|
|
455
|
+
const targetBtn = targetWords.get(key);
|
|
456
|
+
const compareBtn = compareWords.get(key);
|
|
310
457
|
if (targetBtn && compareBtn) {
|
|
311
458
|
result.push({
|
|
312
459
|
word,
|
|
@@ -7,16 +7,21 @@
|
|
|
7
7
|
* Based on: aac-metrics/lib/aac-metrics/metrics.rb
|
|
8
8
|
*/
|
|
9
9
|
import { AACTree } from '../../../core/treeStructure';
|
|
10
|
-
import { MetricsResult } from './types';
|
|
10
|
+
import { MetricsOptions, MetricsResult } from './types';
|
|
11
11
|
export declare class MetricsCalculator {
|
|
12
12
|
private locale;
|
|
13
13
|
/**
|
|
14
14
|
* Main analysis function - calculates metrics for an AAC tree
|
|
15
15
|
*
|
|
16
16
|
* @param tree - The AAC tree to analyze
|
|
17
|
+
* @param options - Optional configuration for metrics calculation
|
|
17
18
|
* @returns Complete metrics result
|
|
18
19
|
*/
|
|
19
|
-
analyze(tree: AACTree): MetricsResult;
|
|
20
|
+
analyze(tree: AACTree, options?: MetricsOptions): MetricsResult;
|
|
21
|
+
/**
|
|
22
|
+
* Identify keyboard/spelling page and calculate base/avg effort
|
|
23
|
+
*/
|
|
24
|
+
private identifySpellingMetrics;
|
|
20
25
|
/**
|
|
21
26
|
* Build reference maps for semantic_id and clone_id frequencies
|
|
22
27
|
*/
|