diff --git a/scripts/verify-campaign-save-normalization.mjs b/scripts/verify-campaign-save-normalization.mjs index 3f08b84..75093a2 100644 --- a/scripts/verify-campaign-save-normalization.mjs +++ b/scripts/verify-campaign-save-normalization.mjs @@ -343,11 +343,12 @@ try { mvp: { unitId: 'liu-bei', name: 'Liu Bei', damageDealt: '88', defeats: '2' }, itemRewards: ['Bean', 'Bean', 10], campaignRewards: { - supplies: ['Bean', 'Bean', 20], - equipment: ['Iron Sword'], - reputation: ['Village Thanks'], - recruits: [{ unitId: 'guan-yu', name: 'Guan Yu' }, { unitId: '', name: 'Broken' }], - unlocks: [{ battleId: 'second-battle-yellow-turban-pursuit', title: 'Next' }, { battleId: '', title: 'Broken' }] + supplies: [' Bean ', 'Bean', 20], + equipment: [' Iron Sword ', 'Iron Sword'], + reputation: ['Village Thanks', ' Village Thanks '], + recruits: [{ unitId: ' guan-yu ', name: ' Guan Yu ' }, { unitId: '', name: 'Broken' }], + unlocks: [{ battleId: ' second-battle-yellow-turban-pursuit ', title: ' Next ' }, { battleId: '', title: 'Broken' }], + note: ' Reward note ' }, completedCampDialogues: ['intro', 'intro', 7], completedCampVisits: { corrupted: true }, @@ -373,7 +374,13 @@ try { malformedReport.firstBattleReport.mvp?.damageDealt === 88 && malformedReport.firstBattleReport.itemRewards.length === 1 && malformedReport.firstBattleReport.campaignRewards?.supplies.length === 1 && + malformedReport.firstBattleReport.campaignRewards?.supplies[0] === 'Bean' && + malformedReport.firstBattleReport.campaignRewards?.equipment.length === 1 && + malformedReport.firstBattleReport.campaignRewards?.reputation.length === 1 && malformedReport.firstBattleReport.campaignRewards?.recruits.length === 1 && + malformedReport.firstBattleReport.campaignRewards?.recruits[0].unitId === 'guan-yu' && + malformedReport.firstBattleReport.campaignRewards?.unlocks[0].battleId === 'second-battle-yellow-turban-pursuit' && + malformedReport.firstBattleReport.campaignRewards?.note === 'Reward note' && malformedReport.firstBattleReport.completedCampDialogues.length === 1 && malformedReport.firstBattleReport.completedCampVisits.length === 0, `Expected malformed report fields to be normalized without discarding the report: ${JSON.stringify(malformedReport)}` diff --git a/src/game/state/campaignState.ts b/src/game/state/campaignState.ts index 1a1ae3e..2cad5d0 100644 --- a/src/game/state/campaignState.ts +++ b/src/game/state/campaignState.ts @@ -856,7 +856,14 @@ function recordOrEmpty(value: unknown): Record { } function uniqueStrings(value: unknown): string[] { - return [...new Set(arrayOrEmpty(value).filter((entry): entry is string => typeof entry === 'string' && entry.length > 0))]; + return [ + ...new Set( + arrayOrEmpty(value) + .filter((entry): entry is string => typeof entry === 'string') + .map((entry) => entry.trim()) + .filter((entry) => entry.length > 0) + ) + ]; } function normalizedRosterUnitIds(roster: UnitData[]) { @@ -1464,18 +1471,18 @@ function cloneCampaignRewardSnapshot(rewards?: CampaignRewardSnapshot): Campaign recruits: arrayOrEmpty(rewardRecord.recruits) .filter(isPlainObject) .map((recruit) => ({ - unitId: typeof recruit.unitId === 'string' ? recruit.unitId : '', - name: typeof recruit.name === 'string' ? recruit.name : '' + unitId: typeof recruit.unitId === 'string' ? recruit.unitId.trim() : '', + name: typeof recruit.name === 'string' ? recruit.name.trim() : '' })) .filter((recruit) => recruit.unitId && recruit.name), unlocks: arrayOrEmpty(rewardRecord.unlocks) .filter(isPlainObject) .map((unlock) => ({ - battleId: typeof unlock.battleId === 'string' ? unlock.battleId : '', - title: typeof unlock.title === 'string' ? unlock.title : '' + battleId: typeof unlock.battleId === 'string' ? unlock.battleId.trim() : '', + title: typeof unlock.title === 'string' ? unlock.title.trim() : '' })) .filter((unlock) => unlock.battleId && unlock.title), - note: typeof rewardRecord.note === 'string' ? rewardRecord.note : undefined + note: typeof rewardRecord.note === 'string' && rewardRecord.note.trim().length > 0 ? rewardRecord.note.trim() : undefined }; }