()
| 446 | } |
| 447 | |
| 448 | async loadSettings() { |
| 449 | const loadedData = await this.loadData(); |
| 450 | const settings = Object.assign( |
| 451 | {}, |
| 452 | DEFAULT_SETTINGS, |
| 453 | loadedData, |
| 454 | ) as QuickAddSettings & { |
| 455 | announceUpdates: QuickAddSettings["announceUpdates"] | boolean; |
| 456 | }; |
| 457 | |
| 458 | if (typeof settings.announceUpdates === "boolean") { |
| 459 | settings.announceUpdates = settings.announceUpdates ? "all" : "none"; |
| 460 | } |
| 461 | |
| 462 | // Heal duplicate choice ids (#1451): a repeated id makes the settings tab's |
| 463 | // keyed {#each} throw each_key_duplicate and render blank (commands keep |
| 464 | // working, so it looks like "corrupted data"). Cheap and idempotent, so it |
| 465 | // runs every load; the next ordinary save rewrites data.json cleaned. No |
| 466 | // data is lost - see dedupeChoicesById. Only touch a real array: a missing |
| 467 | // `choices` already defaults to [] via the merge above, and a null/corrupt |
| 468 | // value is left exactly as-is rather than being silently replaced with [] |
| 469 | // (which a later save would persist, destroying recoverable data). |
| 470 | if (Array.isArray(settings.choices)) { |
| 471 | settings.choices = dedupeChoicesById(settings.choices); |
| 472 | } |
| 473 | |
| 474 | this.settings = settings; |
| 475 | } |
| 476 | |
| 477 | async saveSettings() { |
| 478 | // Immediate, awaitable write (migrations rely on this). Supersede any pending |
no test coverage detected