@willwade/aac-processors 0.0.5 → 0.0.6

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/dist/cli/index.js CHANGED
@@ -142,7 +142,7 @@ commander_1.program
142
142
  .option('--no-exclude-navigation', "Don't exclude navigation buttons (Home, Back)")
143
143
  .option('--no-exclude-system', "Don't exclude system buttons (Delete, Clear, etc.)")
144
144
  .option('--exclude-buttons <list>', 'Comma-separated list of button labels/terms to exclude')
145
- .action((input, output, options) => {
145
+ .action(async (input, output, options) => {
146
146
  try {
147
147
  if (!options.format) {
148
148
  console.error('Error: --format option is required for convert command');
@@ -157,7 +157,7 @@ commander_1.program
157
157
  const tree = inputProcessor.loadIntoTree(input);
158
158
  // Save using output format with same filtering options
159
159
  const outputProcessor = (0, analyze_1.getProcessor)(options.format, filteringOptions);
160
- outputProcessor.saveFromTree(tree, output);
160
+ await outputProcessor.saveFromTree(tree, output);
161
161
  // Show filtering summary
162
162
  let filteringSummary = '';
163
163
  if (filteringOptions.preserveAllButtons) {
@@ -163,7 +163,11 @@ export declare class AACPage implements IAACPage {
163
163
  buttons: AACButton[];
164
164
  parentId: string | null;
165
165
  style?: AACStyle;
166
- constructor({ id, name, grid, buttons, parentId, style, }: {
166
+ locale?: string;
167
+ descriptionHtml?: string;
168
+ images?: any[];
169
+ sounds?: any[];
170
+ constructor({ id, name, grid, buttons, parentId, style, locale, descriptionHtml, images, sounds, }: {
167
171
  id: string;
168
172
  name?: string;
169
173
  grid?: Array<Array<AACButton | null>> | {
@@ -173,6 +177,10 @@ export declare class AACPage implements IAACPage {
173
177
  buttons?: AACButton[];
174
178
  parentId?: string | null;
175
179
  style?: AACStyle;
180
+ locale?: string;
181
+ descriptionHtml?: string;
182
+ images?: any[];
183
+ sounds?: any[];
176
184
  });
177
185
  addButton(button: AACButton): void;
178
186
  }
@@ -152,7 +152,7 @@ class AACButton {
152
152
  }
153
153
  exports.AACButton = AACButton;
154
154
  class AACPage {
155
- constructor({ id, name = '', grid = [], buttons = [], parentId = null, style, }) {
155
+ constructor({ id, name = '', grid = [], buttons = [], parentId = null, style, locale, descriptionHtml, images, sounds, }) {
156
156
  this.id = id;
157
157
  this.name = name;
158
158
  if (Array.isArray(grid)) {
@@ -169,6 +169,10 @@ class AACPage {
169
169
  this.buttons = buttons;
170
170
  this.parentId = parentId;
171
171
  this.style = style;
172
+ this.locale = locale;
173
+ this.descriptionHtml = descriptionHtml;
174
+ this.images = images;
175
+ this.sounds = sounds;
172
176
  }
173
177
  addButton(button) {
174
178
  this.buttons.push(button);
@@ -10,6 +10,45 @@ const treeStructure_1 = require("../core/treeStructure");
10
10
  const plist_1 = __importDefault(require("plist"));
11
11
  const fs_1 = __importDefault(require("fs"));
12
12
  const path_1 = __importDefault(require("path"));
13
+ function isNormalizedPanel(panel) {
14
+ return typeof panel.id === 'string';
15
+ }
16
+ function normalizePanel(panel, fallbackId) {
17
+ const rawId = panel.ID || fallbackId;
18
+ const buttons = Array.isArray(panel.PanelObjects)
19
+ ? panel.PanelObjects.filter((obj) => obj.PanelObjectType === 'Button')
20
+ : [];
21
+ const normalizedButtons = buttons.map((btn) => {
22
+ const firstAction = Array.isArray(btn.Actions) && btn.Actions.length > 0 ? btn.Actions[0] : undefined;
23
+ const isCharSequence = firstAction &&
24
+ (firstAction.ActionType === 'ActionPressKeyCharSequence' ||
25
+ firstAction.ActionType === 'ActionSendKeys');
26
+ const charString = isCharSequence ? firstAction?.ActionParam?.CharString : undefined;
27
+ const targetPanel = firstAction && firstAction.ActionType === 'ActionOpenPanel'
28
+ ? firstAction.ActionParam?.PanelID?.replace(/^USER\./, '')
29
+ : undefined;
30
+ return {
31
+ label: btn.DisplayText || 'Button',
32
+ message: charString || btn.DisplayText || 'Button',
33
+ DisplayColor: btn.DisplayColor,
34
+ DisplayImageWeight: btn.DisplayImageWeight,
35
+ FontSize: btn.FontSize,
36
+ Rect: btn.Rect,
37
+ targetPanel,
38
+ };
39
+ });
40
+ return {
41
+ id: rawId.replace(/^USER\./, ''),
42
+ name: panel.Name || 'Panel',
43
+ buttons: normalizedButtons,
44
+ };
45
+ }
46
+ function normalizeActionParameters(input) {
47
+ if (typeof input === 'object' && input !== null) {
48
+ return { ...input };
49
+ }
50
+ return {};
51
+ }
13
52
  class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
14
53
  constructor(options) {
15
54
  super(options);
@@ -81,41 +120,21 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
81
120
  // Handle both old format (panels array) and new Apple Panels format (Panels dict)
82
121
  let panelsData = [];
83
122
  if (Array.isArray(parsedData.panels)) {
84
- // Old format
85
- panelsData = parsedData.panels;
123
+ panelsData = parsedData.panels.map((panel, index) => {
124
+ if (isNormalizedPanel(panel)) {
125
+ return panel;
126
+ }
127
+ const panelData = panel || {
128
+ PanelObjects: [],
129
+ };
130
+ return normalizePanel(panelData, `panel_${index}`);
131
+ });
86
132
  }
87
133
  else if (parsedData.Panels) {
88
- // Apple Panels format: convert Panels dict to array
89
134
  const panelsDict = parsedData.Panels;
90
135
  panelsData = Object.keys(panelsDict).map((panelId) => {
91
- const panel = panelsDict[panelId];
92
- return {
93
- id: (panel.ID || panelId).replace(/^USER\./, ''), // Strip USER. prefix to maintain original IDs
94
- name: panel.Name || 'Panel',
95
- buttons: (panel.PanelObjects || [])
96
- .filter((obj) => obj.PanelObjectType === 'Button')
97
- .map((btn) => {
98
- const firstAction = Array.isArray(btn.Actions) && btn.Actions.length > 0 ? btn.Actions[0] : undefined;
99
- const isCharSequence = firstAction &&
100
- (firstAction.ActionType === 'ActionPressKeyCharSequence' ||
101
- firstAction.ActionType === 'ActionSendKeys');
102
- const charString = isCharSequence
103
- ? (firstAction.ActionParam?.CharString ?? undefined)
104
- : undefined;
105
- const targetPanel = firstAction && firstAction.ActionType === 'ActionOpenPanel'
106
- ? firstAction.ActionParam?.PanelID?.replace(/^USER\./, '')
107
- : undefined;
108
- return {
109
- label: btn.DisplayText || 'Button',
110
- message: charString || btn.DisplayText || 'Button',
111
- DisplayColor: btn.DisplayColor,
112
- DisplayImageWeight: btn.DisplayImageWeight,
113
- FontSize: btn.FontSize,
114
- Rect: btn.Rect,
115
- targetPanel,
116
- };
117
- }),
118
- };
136
+ const rawPanel = panelsDict[panelId] || { PanelObjects: [] };
137
+ return normalizePanel(rawPanel, panelId);
119
138
  });
120
139
  }
121
140
  const data = { panels: panelsData };
@@ -219,15 +238,24 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
219
238
  Object.values(tree.pages).forEach((page) => {
220
239
  // Translate page names
221
240
  if (page.name && translations.has(page.name)) {
222
- page.name = translations.get(page.name);
241
+ const translatedName = translations.get(page.name);
242
+ if (translatedName !== undefined) {
243
+ page.name = translatedName;
244
+ }
223
245
  }
224
246
  // Translate button labels and messages
225
247
  page.buttons.forEach((button) => {
226
248
  if (button.label && translations.has(button.label)) {
227
- button.label = translations.get(button.label);
249
+ const translatedLabel = translations.get(button.label);
250
+ if (translatedLabel !== undefined) {
251
+ button.label = translatedLabel;
252
+ }
228
253
  }
229
254
  if (button.message && translations.has(button.message)) {
230
- button.message = translations.get(button.message);
255
+ const translatedMessage = translations.get(button.message);
256
+ if (translatedMessage !== undefined) {
257
+ button.message = translatedMessage;
258
+ }
231
259
  }
232
260
  if (button.semanticAction) {
233
261
  const intentStr = String(button.semanticAction.intent);
@@ -304,10 +332,8 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
304
332
  const panelId = `USER.${page.id}`;
305
333
  // Detect actual grid dimensions from the source data
306
334
  let gridCols = 4; // Default fallback
307
- let gridRows = Math.ceil(page.buttons.length / gridCols);
308
335
  if (page.grid && page.grid.length > 0) {
309
336
  // Use actual grid dimensions from source
310
- gridRows = page.grid.length;
311
337
  gridCols = page.grid[0] ? page.grid[0].length : 4;
312
338
  // Find the actual used area to avoid empty space
313
339
  let maxUsedX = 0, maxUsedY = 0;
@@ -322,7 +348,6 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
322
348
  // Use the actual used dimensions if they're reasonable
323
349
  if (maxUsedX > 0 && maxUsedY > 0) {
324
350
  gridCols = maxUsedX + 1;
325
- gridRows = maxUsedY + 1;
326
351
  }
327
352
  }
328
353
  else {
@@ -340,7 +365,6 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
340
365
  else {
341
366
  gridCols = 8; // 8 columns for very large sets
342
367
  }
343
- gridRows = Math.ceil(buttonCount / gridCols);
344
368
  }
345
369
  const panelObjects = page.buttons.map((button, buttonIndex) => {
346
370
  // Find button position in grid layout and convert to Rect format
@@ -379,7 +403,8 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
379
403
  FontSize: button.style?.fontSize || 12,
380
404
  ID: `Button.${button.id}`,
381
405
  PanelObjectType: 'Button',
382
- Rect: rect,
406
+ Rect: rect ?? '{{0, 0}, {100, 25}}',
407
+ Actions: [],
383
408
  };
384
409
  if (button.style?.backgroundColor) {
385
410
  buttonObj.DisplayColor = button.style.backgroundColor;
@@ -414,8 +439,9 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
414
439
  UsesPinnedResizing: false,
415
440
  };
416
441
  });
442
+ const panelsValue = Object.fromEntries(Object.entries(panelsDict).map(([key, value]) => [key, value]));
417
443
  const panelDefinitions = {
418
- Panels: panelsDict,
444
+ Panels: panelsValue,
419
445
  ToolbarOrdering: {
420
446
  ToolbarIdentifiersAfterBasePanel: [],
421
447
  ToolbarIdentifiersPriorToBasePanel: [],
@@ -439,7 +465,7 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
439
465
  if (button.semanticAction?.platformData?.applePanels) {
440
466
  const applePanelsData = button.semanticAction.platformData.applePanels;
441
467
  return {
442
- ActionParam: applePanelsData.parameters,
468
+ ActionParam: normalizeActionParameters(applePanelsData.parameters),
443
469
  ActionRecordedOffset: 0.0,
444
470
  ActionType: applePanelsData.actionType,
445
471
  ID: `Action.${button.id}`,